PAT Ranking(PAT A 1025)

分数值:25分
通过率:28%


1. 问题描述

Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of Zhejiang University. Each test is supposed to run simultaneously in several places, and the rank lists will be merged immediately after the test. Now it is your job to write a program to correctly merge all the rank lists and generate the final rank.

编程能力考试(PAT)是由浙江大学计算机科学与技术学院组织的。每次考试要求在几个地方同时举行,并且在考试之后各地的排名列表应当立即被合并。现在,你的工作是编写一个程序来正确地合并所有的排名列表并生成最终的排名。

Input Specification:
Each input file contains one test case. For each case, the first line contains a positive number N ( ≤ 100 ) N (≤100) N(100), the number of test locations. Then N N N rank lists follow, each starts with a line containing a positive integer K ( ≤ 300 ) K (≤300) K(300), the number of testees, and then K K K lines containing the registration number (a 13-digit number) and the total score of each testee. All the numbers in a line are separated by a space.

每个输入文件包含一个测试用例。对于每个用例,第一行含有一个正数 N ( ≤ 100 ) N(≤100) N(100),即考点的数量。接下来是 N N N 个排名列表,每个列表开头的一行包含一个正整数 K ( ≤ 300 ) K (≤300) K(300),即考生的人数,然后是 K K K 行注册号(一个13位数字)和每个考生的总分。每一行的数字被一个空格隔开。

Output Specification:
For each test case, first print in one line the total number of testees. Then print the final rank list in the following format:

对于每个测试用例,首先在一行打印考生的总人数。然后按下面的格式打印最终的排名列表:

registration_number final_rank location_number local_rank

The locations are numbered from 1 1 1 to N N N. The output must be sorted in nondecreasing order of the final ranks. The testees with the same score must have the same rank, and the output must be sorted in nondecreasing order of their registration numbers.

考点数在 1 1 1 N N N 之间。输出必须按最终排名的非递减次序来排序。相同得分的考生必须是同样的排名,并且输出要按照他们的注册号的非递减次序来排序。

Sample Input:

2
5
1234567890001 95
1234567890005 100
1234567890003 95
1234567890002 77
1234567890004 85
4
1234567890013 65
1234567890011 25
1234567890014 100
1234567890012 85

Sample Output:

9
1234567890005 1 1 1
1234567890014 1 2 1
1234567890001 3 1 2
1234567890003 3 1 2
1234567890004 5 1 4
1234567890012 5 2 2
1234567890002 7 1 5
1234567890013 8 2 3
1234567890011 9 2 4

2. 问题分析

2.1. 整体分析

输入数据的内容是:

  1. 考点数: N ( ≤ 100 ) N(≤100) N(100)
  2. 考生数: K ( ≤ 300 ) K (≤300) K(300)
  3. 考生信息:registration_numberlocal_rank

考生数+考生信息,视为一个数据块,则考生数决定了数据块的长度,考点数决定了数据块的个数。
要求将这些考生信息合并以及重新排序,排序要求满足以下三点要求:

  1. 输出必须按最终排名的非递减次序来排序
  2. 相同得分的考生必须是同样的排名
  3. (相同得分考生)按照他们的注册号的非递减次序来排序

输出的格式要求是:
先输出一行考生总数,设为 num
然后输出 num 行考生信息,如下:

registration_number final_rank location_number local_rank
//     注册号         最终排名     考场序号     考场内排名

2.2. 重点分析

排序的要求较为复杂,应当进一步分析。结合输出样例可知,所谓非递减次序是指——排名整体是升序,局部上同排名的考生按照其注册号的升序来排列,而不同排名的考生的名次仍按其距离第一个“第 1 名”考生的人数决定。用《算法笔记》里的话来说,就是——“分数不同的排名不同,分数相同的排名相同但占用一个排位”。如:

自然顺序成绩排名
第1位考生100分第1名
第2位考生100分第1名
第3位考生99分第3名
第4位考生90分第4名

由例表,不难发现,如果某一考生的“自然顺序”为 k ( ≥ 2 ) k(\ge 2) k(2),则当其成绩与前一位(即第 k − 1 k-1 k1位)考生的成绩相同时,则其“排名”等于前一位的排名;否则当其成绩与前一位考生的成绩不同时,其“排名”的值等于其“自然顺序”的值。

3. 解题思路

由于输入和输出的考生信息复杂,所以优先考虑使用结构体存储考生信息。并创建一个学生数组 stu[30010] N × K ≤ 30000 N\times K \le 30000 N×K30000),供后续排序使用。

/*构建结构体存储学生信息*/
struct Student{
	char id[15]; // 学号
	int score; // 成绩
	int location_number; // 考场序号
	int local_rank; // 考场内排名
}stu[30010];

通过两层 for 循环,遍历所有考场里的所有考生。获取完一个考场的考生信息,即可使用 sort() 算法函数,按成绩(其次按注册号)给考生排出“自然顺序”。
使用 sort() 算法函数前,要为其构建一个比较函数:

/*构建排名比较函数*/
bool cmp(Student a, Student b){
	if(a.score != b.score)
		return a.score > b.score; // 主索引按成绩降序
	else
		return strcmp(a.id, b.id) < 0; // 辅助索引按注册号字典序
}

stu 数组可以在使用时,按考场分区块地使用。假设有 3 个考场,第 1 个考场有 5 名考生,第 2 个有 3 名考生,第 3 个有 4 名考生;则把 [ 0 , 4 ] [0,4] [0,4] 区域视为第 1 考场, [ 5 , 7 ] [5,7] [5,7] 区域视为第 2 考场, [ 8 , 11 ] [8,11] [8,11] 区域视为第 3 考场。每个考场先单独内部排序,最后才将所有考场的考生放在一起排序。

4. 代码参考

#include <cstdio>
#include <cstring>
#include <algorithm> // 导入算法库
using namespace std;

/*构建结构体存储学生信息*/
struct Student{
	char id[15]; // 学号
	int score; // 成绩
	int location_number; // 考场序号
	int local_rank; // 考场内排名
}stu[30010];

/*构建排名比较函数*/
bool cmp(Student a, Student b){
	if(a.score != b.score)
		return a.score > b.score; // 主索引按成绩降序
	else
		return strcmp(a.id, b.id) < 0; // 辅助索引按注册号字典序
}

int main(){
	int n, k, num = 0; // 声明考场数变量、考场内考生数变量、考生总数变量
	scanf("%d", &n);
	for(int i = 1; i <= n; i++){ // 至少共有一个考场
		scanf("%d", &k);
		for(int j = 0; j < k; j++){ // 获取考生基本信息
			scanf("%s %d", stu[num].id, &stu[num].score);
			stu[num].location_number = i;
			num++; // 统计考生总数
		}
		sort(stu + num - k, stu + num, cmp); // 考场内考生按成绩排序
		stu[num - k].local_rank = 1;
		for(int j = num - k + 1; j < num; j++){ // 按需求规则指定名次
			if(stu[j].score == stu[j-1].score)
				stu[j].local_rank = stu[j-1].local_rank;
			else
				stu[j].local_rank = j + 1 - (num - k);
		}
	}
	printf("%d\n", num);
	sort(stu, stu + num, cmp); // 总体考生按成绩排序
	int rank = 1; //  初始化总名次
	for(int i = 0; i < num; i++){ // 按需求规则指定名次
		if(i > 0 && stu[i].score != stu[i-1].score)
			rank = i + 1;
		printf("%s ", stu[i].id);
		printf("%d %d %d\n", rank, stu[i].location_number, stu[i].local_rank);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值