【算法学习记录-排序题】【PAT A1025】PAT Ranking

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 ranklists will be merged immediately after the test. Now it is your job to write a program to correctly merge all the ranklists and generate the final rank.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive number N (≤100), the number of test locations. Then N ranklists follow, each starts with a line containing a positive integer K (≤300), the number of testees, and then 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.

Output Specification:

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

registration_number final_rank location_number local_rank

The locations are numbered from 1 to 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.

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

题意:

有n个考场,每个考场有若干考生。

现给出各个考场所有考生的准考证号与分数,要求按分数从高到低分别进行①单考场内排序②总排序。

最终输出参加考试的考生数以及每个考生的①准考证号②总排名③考场号④考场内排名

思路:

1、排序的逻辑

①按分数从高到低排序

②分数相同时,按准考证号从小到大排序

2、所需要的信息及信息的存储

①对于单个学生student,需要对应的准考证号id,分数score,考场号location_number,考场内排名local_rank,总排名sum_rank——结构体Student,并创建一个足够大的结构体数组

②此外还需要总考场数n,总考生数num,单个考场内的考生数k——int型变量

3、排序逻辑的实现

1 bool cmp(Student a, Student b) {
2     if (a.score != b.score) {
3         return a.score > b.score;
4     } else {
5         return strcmp(a.id, b.id) < 0;
6     }
7 }

4、main()  分步分析

主要分为两个部分:

(1)给单个考场内的考生排名

①有n个考场,因此最外层要有for循环从1到n遍历每个考场

1 for (int i = 1; i <= n; i++) {
2 }

②每个考场内有k个学生,因此内层要有for循环从0到k-1遍历每个学生

1 for (int j = 0; j < k; j++) {
2 }

③接收输入的准考证号id与分数score,按顺序存入结构体数组中

1 scanf("%s %d", stu[num].id, &stu[num].score);

④当前考场的学生遍历完后,调用排序函数sort()对当前考场内的所有考生按排序逻辑进行排序

1 sort(stu, stu + k, cmp);

⑤按④的排序结果,依次给每个考生的考场内排名local_rank赋值

1 stu[0].local_rank = 1;  //第一个考生的排名为1
2 for (int j = 1; j < k; j++) {
3     if (stu[j].score == stu[j - 1].score) {
4         stu[j].local_rank = stu[j - 1].local_rank; //分数相同则排名相同
5     } else {
6         stu[j].local_rank = j + 1; //分数不同则+1
7     }
8 }

(2)给所有的考生排名

⑥调用排序函数sort()对所有考生按排序逻辑进行排序(代码同④)

⑦按⑥的排序结果,依次给每个考生的总排名sum_rank赋值(代码同⑤)

5、踩到了第一个坑

只开一个Student类型的数组,但是要存放多个考场的考生信息,因此遍历和排序时不能简单的从下标0开始

解决:

引入新变量 总考生数num

于是可知,每次接收完一个新考场的考生数据时,此考场考生对应的下标范围是num - k ~ num

6、main()  雏形

 1 scanf("%d", &n); //考场数
 2 for (int i = 1; i <= n; i++) { //考场号,要从1开始
 3     scanf("%d", &k); //当前考场人数
 4
 5     /*录入数据*/
 6     for (int j = 0; j < k; j++) {
 7         scanf("%s %d", stu[num].id, &stu[num].score);
 8         stu[num].location_number = i;
 9         num++; //通过这个计算总考生数
10     }
11
12     /*对刚录入的这个考场考生进行排序并赋名次*/
13     sort(stu + num - k, stu + num, cmp);
14     stu[num - k].local_rank = 1;
15     for (int j = num - k + 1; j < num; j++) {
16         if (stu[j].score == stu[j - 1].score) {
17             stu[j].local_rank = stu[j - 1].local_rank;
18         } else {
19             stu[j].local_rank = j + 1 - (num - k);//j为此考生之前的人数,- (num - k)为去掉前面其他考场的人数,+ 1后即得到此考生在本考场的排名
20         }
21     }
22
23 }
24
25 /*对所有考生进行排序并赋名次*/
26 sort(stu, stu + num, cmp);
27 stu[0].sum_rank = 1;
28 for (int i = 1; i < num; i++) {
29     if (stu[i].score == stu[i - 1].score) {
30         stu[i].sum_rank = stu[i - 1].sum_rank;
31     } else {
32         stu[i].sum_rank = i + 1;
33     }
34 }
35     

7、优化

总排名sum_rank是在整个程序的最后才得到的

它之后紧跟着的就是要将sum_rank输出——额外去存储的意义不大

并且sum_rank的值只有两种情况①和前一个相同②i + 1——值的计算简单,没有其他的相关项

所以考虑将“计算出总排名→存入sum_rank→输出stu[i].sum_rank”简化为“计算出总排名→输出总排名”

 1 sort(stu, stu + num, cmp);
 2 int r = 1; //r即为总排名,初始为1
 3 for (int i = 0; i < num; i++) {
 4     //i > 0:从第二个考生开始(stu[0]为第一个考生)
 5     //stu[i].score != stu[i - 1].score:
 6     //若两人分数相同,则总排名r相同;
 7     //若不同,则后一个人的排名为其前面的人数 i + 1;
 8     if (i > 0 && stu[i].score != stu[i - 1].score) {
 9     r = i + 1;
10     }
11 }

8、main() 最终形态

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 struct Student {
 6     char id[15];
 7     int score;
 8     int location_number;
 9     int local_rank;
10     int sum_rank; //test
11 }stu[30010];
12 bool cmp(Student a, Student b) {
13     if (a.score != b.score) {
14         return a.score > b.score;
15     } else {
16         return strcmp(a.id, b.id) < 0;
17     }
18 }
19 int main() {
20     int n, k, num = 0;
21     scanf("%d", &n);
22     for (int i = 1; i <= n; i++) {
23         scanf("%d", &k);
24         for (int j = 0; j < k; j++) {
25             scanf("%s %d", stu[num].id, &stu[num].score);
26             stu[num].location_number = i;
27             num++;
28         }
29         sort(stu + num - k, stu + num, cmp);
30         stu[num - k].local_rank = 1;
31         for (int j = num - k + 1; j < num; j++) {
32             if (stu[j].score == stu[j - 1].score) {
33                 stu[j].local_rank = stu[j - 1].local_rank;
34             } else {
35                 stu[j].local_rank = j + 1 - (num - k);
36             }
37         }
38     }
39     printf("%d\n", num);
40     sort(stu, stu + num, cmp);
41     int r = 1;
42     for (int i = 0; i < num; i++) {
43         if (i > 0 && stu[i].score != stu[i - 1].score) {
44             r = i + 1;
45         }
46         printf("%s ", stu[i].id);
47         printf("%d %d %d\n", r, stu[i].location_number, stu[i].local_rank);
48     }
49     return 0;
50 }

原文地址:https://www.cnblogs.com/Bananice/p/12231523.html

时间: 2024-07-30 17:36:19

【算法学习记录-排序题】【PAT A1025】PAT Ranking的相关文章

【算法学习记录-排序题】【PAT A1012】The Best Rank

To evaluate the performance of our first year CS majored students, we consider their grades of three courses only: C - C Programming Language, M - Mathematics (Calculus or Linear Algrbra), and E - English. At the mean time, we encourage students by e

【算法学习记录-排序题】【PAT A1062】Talent and Virtue

About 900 years ago, a Chinese philosopher Sima Guang wrote a history book in which he talked about people's talent and virtue. According to his theory, a man being outstanding in both talent and virtue must be a "sage(圣人)"; being less excellent

算法学习记录-查找——平衡二叉树(AVL)

排序二叉树对于我们寻找无序序列中的元素的效率有了大大的提高.查找的最差情况是树的高度.这里就有问题了,将无序数列转化为 二叉排序树的时候,树的结构是非常依赖无序序列的顺序,这样会出现极端的情况. [如图1]: 这样的一颗二叉排序树就是一颗比较极端的情况.我们在查找时候,效率依赖树的高度,所以不希望这样极端情况出现,而是希望元素比较均匀 的分布在根节点两端. 技术参考:fun4257.com/ 问题提出: 能不能有一种方法,使得我们的二叉排序树不依赖无序序列的顺序,也能使得我们得到的二叉排序树是比

算法学习记录-栈的应用--表达式运算

前面做了栈的基本操作 总感觉需要做一个实际的例子来检验一下. 这里我将用栈来做一个简单的四则运算. 目标比较简单: 做一个带小括号(“()”)的四则运算,如果要加入到中括号(“[]”)或者大括号(“{}”),依次类推. 求一个表达式: 用下面这个算是做例子,程序最后应该可以算出任何带小括号的运算. 3+(32-6)*9+5*3-(3*(65-15)/5)+12; 方法一:后缀法. 1.了解中缀和后缀表示法 中缀表示法:刚才的那个算是就是中缀表示法,我们通常看到的数学符号就是中缀表示法,即数字在计

算法学习之排序的那些事(一)

????????排序的目的就是对一组无序的元素按照一定的次序排列起来.那么总的来说排序要做到事情就只有两件,找到各个元素按照一定次序排列后的位置并把各个元素移动到其所对应的位置.由此看出决定一个排序算法效率的因素也就是这两个: 寻找元素位置所消耗的时间 移动元素到其对应位置所消耗的时间 下面是一些常用的排序算法: 冒泡排序: 算法描述:算法比较简单就不多描述了. 实现步骤: 对N个元素做N-1次循环(每次循环至少可以把一个元素移动的正确的位置,N-1次循环后便把N个元素排列好了) 每次循环进行N

算法学习之排序算法:插入排序(直接插入排序、折半插入排序、2-路插入排序)

引言: 插入排序作为最简单易于理解的排序算法,基本实现比较简单.本文详细介绍直接插入排序,并给出实现,简单的介绍折半插入排序,并给出2-路插入排序和表插入排序两种插入排序,但并未给出具体实现. 一.直接插入排序 直接插入排序的基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的.记录数增1的有序表. 算法描述: 步骤1.将待排序的一组记录中的第1个记录拿出来作为一组有序的记录(当然此时该组记录仅有1个记录). 步骤2.依次将待排序的一组记录中的记录拿出来插入到前面已排好序的记录中. 步

算法学习之排序算法:堆排序

要了解堆排序,首先要了解堆的概念,因为本文主要研究堆排序的算法,此处对数据结构堆只是给出概念:n个元素的序列{k1,k2,...kn},当且仅当满足如下关系时,称之为堆. k[i] <= k[2i]且k[i] <= k[2i+1] (或 k[i] >= k[2i]且k[i] >= k[2i+1]) 比如:序列96.83.27.38.11.09(或12.36.24.85.47.30.53.91)都是堆. 如果将堆对应的一维数组看成是一个二叉树,则堆的含义表明:完全二叉树中所有非终端结

算法学习之排序算法:归并排序

"归并"的含义是将两个或两个以上的有序表组合成一个新的有序表.无论是顺序存储还是链表存储结构,都可在O(m+n)的时间量级上实现. 归并排序又是一类不同的排序方法.假设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2个为2或1的有序子序列:再两两归并,....... ,如此重复,直至得到一个长度为n的有序序列为止. 初始关键字:[49]   [38]   [65]   [97]   [76]   [13]   [27] A       A

算法学习之排序算法:选择排序

选择排序:每一趟在n-i+1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录. 一.简单选择排序 一趟选择排序操作: 通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换之. 对L[1...n]中记录进行简单选择排序的算法为:令i从1至n-1,进行n-1趟选择操作.简单选择排序过程中,所需进行记录移动的操作次数较少,然而,无论记录的初始排列如何,所需关键字间的比较次数相同.因此,总的时间复杂度为O(n^2)