PAT甲级刷题之路——1075

一道排序题

按照某种规则排序

PAT甲级1075 PAT Judge

原题如下

The ranklist of PAT is generated from the status list, which shows the scores of the submissions. This time you are supposed to generate the ranklist for PAT.

Input Specification:
Each input file contains one test case. For each case, the first line contains 3 positive integers, N (≤10
​4
​​ ), the total number of users, K (≤5), the total number of problems, and M (≤10
​5
​​ ), the total number of submissions. It is then assumed that the user id’s are 5-digit numbers from 00001 to N, and the problem id’s are from 1 to K. The next line contains K positive integers p[i] (i=1, …, K), where p[i] corresponds to the full mark of the i-th problem. Then M lines follow, each gives the information of a submission in the following format:
user_id problem_id partial_score_obtained
where partial_score_obtained is either −1 if the submission cannot even pass the compiler, or is an integer in the range [0, p[problem_id]]. All the numbers in a line are separated by a space.
Output Specification:
For each test case, you are supposed to output the ranklist in the following format:
rank user_id total_score s[1] … s[K]
where rank is calculated according to the total_score, and all the users with the same total_score obtain the same rank; and s[i] is the partial score obtained for the i-th problem. If a user has never submitted a solution for a problem, then “-” must be printed at the corresponding position. If a user has submitted several solutions to solve one problem, then the highest score will be counted.

The ranklist must be printed in non-decreasing order of the ranks. For those who have the same rank, users must be sorted in nonincreasing order according to the number of perfectly solved problems. And if there is still a tie, then they must be printed in increasing order of their id’s. For those who has never submitted any solution that can pass the compiler, or has never submitted any solution, they must NOT be shown on the ranklist. It is guaranteed that at least one user can be shown on the ranklist.
Sample Input:
7 4 20
20 25 25 30
00002 2 12
00007 4 17
00005 1 19
00007 2 25
00005 1 20
00002 2 2
00005 1 15
00001 1 18
00004 3 25
00002 2 25
00005 3 22
00006 4 -1
00001 2 18
00002 1 20
00004 1 15
00002 4 18
00001 3 4
00001 4 2
00005 2 -1
00004 2 0
Sample Output:
1 00002 63 20 25 - 18
2 00005 42 20 0 22 -
2 00007 42 - 25 - 17
2 00001 42 18 18 4 2
5 00004 40 15 0 25 -

题目意思

输入:
已知用户数量N、题目总数K、总提交数M;
已知每道题的总分p[i](编译未通过输入-1);
已知每次提交的用户ID、题目号以及得分;
输出:
按照排名顺序输出(分别输出排名、ID、总分、每道题最高得分,若没过编译(不是没过编译,是没有提交输出’-’!!,再一次没看清题orz)则输出’-’):其中分数相同排名相同;若排名相同则按照提交的最完美的题目数从大到小输出;若前两者都相同则按照ID增序输出。
并且若没有编译过一道题或者没有提交,则不进入排名。

自己的想法

构建一个包括ID、总分、排名、每道题最高得分、完美过题数、是否编译成功的结构体;
用sort函数根据总分数排序然后标注好每个用户的rank;
在构建一个根据输出规则的cmp函数,再用sort函数排序并输出。

答案反馈

花了一个小时才AC,其中debug了好久
PAT甲级刷题之路——1075_第1张图片
总结一下我遇到的坎:

  1. 没看清题orz,题目让没有提交过的题输出’-’,结果我一开始把没有编译成功的题也输出了’-’,因为这个样例一直过不了
  2. 在结构体初始化的时候,若数组全赋值为0,可以用一下代码
int a[maxn]={0};

但是赋值为其他数,比如-1,则需要一个一个赋值,否则其他未赋值的默认还是0

int a[4]={-1,-1,-1,-1};
  1. 在替换每个用户的每道题的最高分数时,先替换了再判断它是否完美过题数需不需要+1,结果导致完美过题数一直为0,错误代码如下:
//判断是否这道题的得分比以往得分高,高则替换
			if (user[id].top[pro_id] < s) {
				user[id].score = user[id].score + s - user[id].top[pro_id];
				user[id].top[pro_id] = s;
			}
			//只有之前这道题没拿过perfect才能替换
			if (s == p[pro_id] && user[id].top[pro_id] != p[pro_id]) { user[id].perfect++; }

将两个if换个位置即可,正确代码:

//只有之前这道题没拿过perfect才能替换
			if (s == p[pro_id] && user[id].top[pro_id] != p[pro_id]) { user[id].perfect++; }
			//判断是否这道题的得分比以往得分高,高则替换
			if (user[id].top[pro_id] < s) {
				user[id].score = user[id].score + s - user[id].top[pro_id];
				user[id].top[pro_id] = s;
			}

代码

附上乱七八糟的AC代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cmath>
#include<vector>
#include<cstdlib>
#include<set>
#include<queue>
#include<map>
#include<stack>
using namespace std;
int p[10];
const int maxn = 10005;
struct users{
	int id, rank, score=0, perfect=0;
	bool flag = false;
	int top[10] = { 0};
	bool flag2[10] = { false };
}user[maxn];
bool cmp1(users a, users b) {
	return a.score > b.score;
}
bool cmp2(users a, users b) {
	if (a.rank != b.rank) {
		return a.rank < b.rank;
	}
	else if (a.perfect != b.perfect) {
		return a.perfect > b.perfect;
	}
	else {
		return a.id < b.id;
	}
}
int main() {
	int n, k, m;
	cin >> n >> k >> m;
	for (int i = 1; i <= k; i++) {
		cin >> p[i];
	}
	//初始化结构体
	//fill(user[0].score, user[maxn - 1].score, 0);
	//fill(user[0].perfect, user[maxn - 1].perfect, 0);
	//fill(user[0].top, user[maxn - 1].top, -1);
	//fill(user[0].flag, user[maxn - 1].flag, false);
	for (int i = 0; i < m; i++) {
		int id, pro_id, s;
		cin >> id >> pro_id >> s;
		user[id].id = id;
		user[id].flag2[pro_id] = true;
		if (s != -1) {
			user[id].flag = true;
			//只有之前这道题没拿过perfect才能替换
			if (s == p[pro_id] && user[id].top[pro_id] != p[pro_id]) { user[id].perfect++; }
			//判断是否这道题的得分比以往得分高,高则替换
			if (user[id].top[pro_id] < s) {
				user[id].score = user[id].score + s - user[id].top[pro_id];
				user[id].top[pro_id] = s;
			}
		}
	}
	//根据总分获取排名
	sort(user + 1, user + n + 1, cmp1);//id是从1-n
	int rk = 0, index = -1;
	for (int i = 1; i <= n; i++) {
		user[i].rank = rk;
		if (user[i].score != index) {
			user[i].rank = i; index = user[i].score; rk = i;
		}
	}
	//再根据输出规则获取排名
	sort(user + 1, user + n + 1, cmp2);
	for (int i = 1; i <= n; i++) {
		if (user[i].flag == true) {
			printf("%d %05d %d", user[i].rank, user[i].id, user[i].score);
			for (int j = 1; j <= k; j++) {
				//cout << "--"<
				if (user[i].flag2[j] == false) {
					printf(" -");
				}
				else {
					printf(" %d", user[i].top[j]);
				}
			}
			printf("\n");
		}
	}
	return 0;
}

结语

又是看清题目看清题目啊!!!这道题是很经典的排序题,也完全没有绕什么弯,主要是自己写代码的时候思想有点混乱,想到哪写到哪,导致花费时间较长同时容易出错,希望写博客记录自己的错误的同时能把自己这种死毛病给改了吧!

你可能感兴趣的