PAT-ADVANCED1075/Data Structures and Algorithms7-15——PAT Judge

我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED

我的Data Structures and Algorithms代码仓:https://github.com/617076674/Data-Structures-and-Algorithms

原题链接:

PAT-ADVANCED1075:https://pintia.cn/problem-sets/994805342720868352/problems/994805393241260032

Data Structures and Algorithms7-15:https://pintia.cn/problem-sets/16/problems/677

题目描述:

PAT-ADVANCED1075、Data Structures and Algorithms7-15:

题目翻译:

1075 PAT判题系统

状态列表显示了每次提交的分数,PAT的排名就是根据这个状态列表生成的。现在你需要生成PAT的排名。

输入格式:

每个输入文件包含一个测试用例。对每个测试用例,第一行包含3个正整数,N(<= 10 ^ 4),代表用户总数,K(<= 5)代表题目总数,以及M(<= 10 ^ 5),代表提交总数。假设用户的编号是一个5位数,且在00001 ~ N的范围内,问题编号在1 ~ K的范围内。接下来的1行包含K个正整数p[i](i = 1, ..., K),其中p[i]代表第i个问题的满分值。接下来的M行,每行以下述形式给出一次提交的信息:

user_id problem_id partial_score_obtained

如果编译失败,则partial_score_obtained是-1。如果编译通过,则partial_score_obtained是一个[0, p[problem_id]]之间的值。一行中的所有数字由一个空格隔开。

输出格式:

对每个测试用例,你需要按下述形式输出排名列表:

rank user_id total_score s[1] ... s[K]

排名rank是根据total_score由大到小的顺序生成的,拥有相同total_score的用户的排名相同。s[i]是i号问题的得分。如果某个用户没有对某问题没有进行过任何提交,则在相应位置输出“-”。如果某用户对同个问题有多次提交,则输出最高分数。

排名列表必须根据rank的非降序排列。对有相同排名的用户,必须根据全对题数进行非升序排列。如果rank和全对题数均相同,则根据id的増序排列。对于那些从来没有提交过能编译成功的用户,以及那些从来没有提交过任何解决方案的用户,他们不应该出现的排名列表中。题目保证在排名列表中至少有一个用户能被输出。

输入样例:

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

输出样例:

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 -

知识点:排序

思路:先筛选出需要显示的用户,再对需要显示的用户进行排名

构建一个结构体scoreConsist来保存用户id信息,用户排名信息,用户的总分、各题分数、全对题数。其中结构体中存储分数的数组int score[7]需要初始化为-2,以和编译失败的-1和编译成功但得分为0的情况相区分

再定义一个数组scoreConsist scores[10001],scores[i]保存编号为i的用户的得分信息。为什么用数组呢?因为我们在多次提交中取的是得分的最大值,对于某次输入,把用户id当作数组的下标能用O(1)的时间复杂度定位到该用户id原有的分数。

既然数组的下标已经代表了用户的id,那为什么结构体scoreConsist中还需要保存用户id信息呢?

因为排序之后数组的下标就不再和用户id值相对应了。

为什么要强调先筛选出需要显示的用户,再对需要显示的用户进行排名呢?

因为我的排名的生成过程时根据该用户在vector<scoreConsist> scoreConsists的索引来生成的,如果在遍历vector<scoreConsist> scoreConsists时有需要跳过不显示的用户,那么排名编号就会出错。一开始我就是犯了这个错误,导致测试点4无法通过。

注意看样例00005编号的第2题,编译失败所以显示得分0。而00004编号的第2题虽然编译成功,但得分是0所以显示0。

根据题意,只有那些从来没有提交过能编译成功的用户,以及那些从来没有提交过任何解决方案的用户,才不包含在排名列表中。对于有过提交且编译通过的用户,可能其得分是0,其总得分也是0,但应该将这些用户包含在排名列表中

时间复杂度是O(NlogN)。空间复杂度是O(N)。

C++代码:

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

/*
	 scoreConsist用于存储一个人的得分情况 
*/
struct scoreConsist {
	int id;
	int rank;
	//score[0]存储总分,score[1] ~ score[K]存储各题分数,score[K + 1]存储全对题数 
	//初始化值全为-2,和编译失败结果-1,编译通过但得分为0相区别开 
	int score[7] = {-2, -2, -2, -2, -2, -2, -2};	
};

int N, K, M;
scoreConsist scores[10001];	 //scores[i]存储第i号人的得分情况 

bool cmp(scoreConsist s1, scoreConsist s2);

int main() {
	cin >> N >> K >> M;
	int problems[K + 1];	//存储各题满分值 
	for(int i = 1; i <= K; i++) {
		cin >> problems[i];
	}
	int user_id, problem_id, partial_score_obtained;
	for(int i = 0; i < M; i++) {
		cin >> user_id >> problem_id >> partial_score_obtained;
		scores[user_id].id = user_id;
		if(partial_score_obtained > scores[user_id].score[problem_id]) {
			scores[user_id].score[problem_id] = partial_score_obtained;
		}
	}
	for(int i = 1; i <= N; i++) {
		int sum = 0;
		int perfect = 0;
		for(int j = 1; j <= K; j++) {
			if(scores[i].score[j] == -1 || scores[i].score[j] == -2) {
				continue;
			}
			sum += scores[i].score[j];
			if(scores[i].score[j] == problems[j]) {
				perfect++;
			}
		}
		scores[i].score[0] = sum;	//计算总分 
		scores[i].score[K + 1] = perfect;	//计算全对题数 
	}
	vector<scoreConsist> scoreConsists;
	for(int i = 1; i <= N; i++) {
		bool flag = false;
		for(int j = 1; j <= K; j++) {
			if(scores[i].score[j] != -2 && scores[i].score[j] != -1) {
				flag = true;
				break;
			}
		}
		if(!flag) {
			continue;
		}
		scoreConsists.push_back(scores[i]);	//滤除去不需要显示的数据 
	}
	sort(scoreConsists.begin(), scoreConsists.end(), cmp);	//对需要显示的数据进行题目要求的排序 
	for(int i = 0; i < scoreConsists.size(); i++) {
		scoreConsists[i].rank = i + 1;
		if(i > 1 && scoreConsists[i].score[0] == scoreConsists[i - 1].score[0]) {
			scoreConsists[i].rank = scoreConsists[i - 1].rank;
		}
		printf("%d %05d %d ", scoreConsists[i].rank, scoreConsists[i].id, scoreConsists[i].score[0]);
		for(int j = 1; j <= K; j++) {
			if(scoreConsists[i].score[j] == -2) {	//如果是-2,说明根本没有提交,显示“-” 
				printf("-");
			} else if(scoreConsists[i].score[j] == -1) {	//如果是-1,说明提交了但是编译失败,根据样例应该显示“0” 
				printf("0");
			} else {
				printf("%d", scoreConsists[i].score[j]);
			}
			if(j != K) {
				printf(" ");
			} else {
				printf("\n");
			}
		}
	}
}

bool cmp(scoreConsist s1, scoreConsist s2) {
	if(s1.score[0] == s2.score[0]) {
		if(s1.score[K + 1] == s2.score[K + 1]) {
			return s1.id < s2.id;
		} else {
			return s1.score[K + 1] > s2.score[K + 1];
		}
	} else {
		return s1.score[0] > s2.score[0];
	}
}

C++解题报告:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值