【算法学习记录-排序题】【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 emphasizing on their best ranks -- that is, among the four ranks with respect to the three courses and the average grade, we print the best rank for each student.

For example, The grades of C, M, E and A - Average of 4 students are given as the following:

StudentID  C  M  E  A
310101     98 85 88 90
310102     70 95 88 84
310103     82 87 94 88
310104     91 91 91 91

Then the best ranks for all the students are No.1 since the 1st one has done the best in C Programming Language, while the 2nd one in Mathematics, the 3rd one in English, and the last one in average.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 2 numbers N and M (≤2000), which are the total number of students, and the number of students who would check their ranks, respectively. Then N lines follow, each contains a student ID which is a string of 6 digits, followed by the three integer grades (in the range of [0, 100]) of that student in the order of C, M and E. Then there are M lines, each containing a student ID.

Output Specification:

For each of the M students, print in one line the best rank for him/her, and the symbol of the corresponding rank, separated by a space.

The priorities of the ranking methods are ordered as A > C > M > E. Hence if there are two or more ways for a student to obtain the same best rank, output the one with the highest priority.

If a student is not on the grading list, simply output N/A.

Sample Input:

5 6
310101 98 85 88
310102 70 95 88
310103 82 87 94
310104 91 91 91
310105 85 90 90
310101
310102
310103
310104
310105
999999

Sample Output:

1 C
1 M
1 E
1 A
3 A
N/A

题意:

n个学生,现分别给出每个学生的3科成绩C、M、E,又有A为平均分

给出m个查询,输入学生ID,输出A、C、M、E中最高的排名及对应的是哪个

①若多个排名相同,则按A>C>M>E输出最高优先级的

②若查询的学生ID不存在,则输出N/A

思路:

0、对比分析

【A1012】在《算法笔记(胡凡)》中,按训练顺序是排在【A1025】和【A1062】两道排序题之后

因为那两题是最基础的仅单项数据的排序,而这一题扩展到了多项(4项)数据的排序

在刚看到这题时因为要进行多项数据的排序而陷入了混乱

现在复盘梳理时,我认为 从 单项数据排序 扩展到 多项数据排序 的思路会更加清晰且易于理解

1、先从单项数据排序开始

我们假设现在只有一门科目X

①结构体

1 struct Student {
2     int id;    //学生id
3     int grade;    //分数
4 }stu[2010];  //题目给出N《=2000

②排序函数cmp

1 bool cmp(Student a, Student b) {
2     return a.grade> b.grade;
3 }

③存放排名的数组Rank(※这里踩过一个坑:rank是关键字,所以要写作Rank)

在之前的【A1025】和【A1062】中,id只用于输出,故都是常规地使用char类型数组存放

而这一题中,id要担当从 分数Student.grade 到 排名Rank 的对应 的责任

如果在Student中将id设为char[6],那Rank中就既要存放int型的排名,又要存放char[]型的id——显然,就算强行实现,也非常麻烦

考虑到题目中的id为6位0-9的数字,故我们将id设为int类型,而Rank的大小则开为[1000000],其下标就包含了100000~999999的所有可能的ID

即Rank[Student.id] = Student.grade,每个下标对应的即为此ID学生的排名

1 int Rank[10000000] = {0};

④main()

 1 int main() {
 2     //总计有n个学生,m个查询
 3     scanf("%d%d", &n, &m);
 4     for (int i = 0; i < n; i++) {
 5         scanf("%d%d", &stu[i].id, &stu[i].grade);
 6     }
 7     //对n个学生的成绩进行排序
 8     sort(stu, stu + n, cmp);
 9     //第一名的排名为1
10     Rank[stu[0].id] = 1;
11     //剩下学生的排名
12     for (int i = 1; i < n; i++) {
13         if (stu[i].grade == stu[i - 1].grade) {
14             Rank[stu[i].id] = Rank[stu[i - 1].id];
15         } else {
16             Rank[stu[i].id] = i + 1;
17         }
18     }
19     //m个查询
20     for (int i = 0; i < m; i++) {
21         scanf("%d", &query);
22         if (Rank[query] == 0) {
23             printf("N/A\n");
24         } else {
25             printf("%d %c\n", Rank[query]);
26         }
27     }
28     return 0;
29 }    

2、再扩展到多项数据排序

①结构体修改

1 struct Student {
2     int id;
3     int grade[4];
4 }stu[2010];

②排序函数cmp修改

1 int now;    //标识当前是A、C、M、E中的哪个科目
2
3 bool cmp(Student a, Student b) {
4     return a.grade[now] > b.grade[now];
5 }

③还需要的两个数组

1 char course[4] = {‘A‘, ‘C‘, ‘M‘, ‘E‘};    //按优先级排序更方便
2
3 int Rank[10000000][4] = {0};

④main() : 录入成绩

1 for (int i = 0; i < n; i++) {
2     scanf("%d%d%d%d", &stu[i].id, &stu[i].grade[1], &stu[i].grade[2], &stu[i].grade[3]);    //C、M、E
3     stu[i].grade[0] = round((stu[i].grade[1] + stu[i].grade[2] + stu[i].grade[3]) / 3.0) + 0.5;    //A
4 }

⑤main() : 排名

 1 for (now = 0; now < 4; now++) {    //四个科目分别排
 2
 3     //内部就和单数据排序相同了
 4     sort(stu, stu + n, cmp);
 5     Rank[stu[0].id][now] = 1;
 6     for (int i = 1; i < n; i++) {
 7         if (stu[i].grade[now] == stu[i - 1].grade[now]) {
 8             Rank[stu[i].id][now] = Rank[stu[i - 1].id][now];
 9         } else {
10             Rank[stu[i].id][now] = i + 1;
11         }
12     }
13
14 }

⑥main() : 查询

 1 for (int i = 0; i < m; i++) {
 2     scanf("%d", &query);
 3     if (Rank[query][0] == 0) {
 4         printf("N/A\n");
 5     } else {
 6         int k = 0;  //因有A>C>M>E的优先级,故这里设初值0
 7         for (int j = 0; j < 4; j++) {
 8             if (Rank[query][j] < Rank[query][k]) {
 9                 k = j;
10             }
11         }
12         printf("%d %c\n", Rank[query][k], course[k]);
13     }
14 }

3、题解

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 struct Student {
 7     int id;
 8     int grade[4];
 9 }stu[2010];
10
11 char course[4] = {‘A‘, ‘C‘, ‘M‘, ‘E‘};
12 int Rank[10000000][4] = {0};
13 int now;
14
15 bool cmp(Student a, Student b) {
16     return a.grade[now] > b.grade[now];
17 }
18 int main() {
19     int n, m, query;
20     scanf("%d%d", &n, &m);
21     for (int i = 0; i < n; i++) {
22         scanf("%d%d%d%d", &stu[i].id, &stu[i].grade[1], &stu[i].grade[2], &stu[i].grade[3]);
23         stu[i].grade[0] = round((stu[i].grade[1] + stu[i].grade[2] + stu[i].grade[3]) / 3.0) + 0.5;
24     }
25     for (now = 0; now < 4; now++) {
26         sort(stu, stu + n, cmp);
27         Rank[stu[0].id][now] = 1;
28         for (int i = 1; i < n; i++) {
29             if (stu[i].grade[now] == stu[i - 1].grade[now]) {
30                 Rank[stu[i].id][now] = Rank[stu[i - 1].id][now];
31             } else {
32                 Rank[stu[i].id][now] = i + 1;
33             }
34         }
35     }
36     for (int i = 0; i < m; i++) {
37         scanf("%d", &query);
38         if (Rank[query][0] == 0) {
39             printf("N/A\n");
40         } else {
41             int k = 0;
42             for (int j = 0; j < 4; j++) {
43                 if (Rank[query][j] < Rank[query][k]) {
44                     k = j;
45                 }
46             }
47             printf("%d %c\n", Rank[query][k], course[k]);
48         }
49     }
50     return 0;
51 }

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

时间: 2024-11-08 13:30:06

【算法学习记录-排序题】【PAT A1012】The Best Rank的相关文章

【算法学习记录-排序题】【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 i

【算法学习记录-排序题】【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.了解中缀和后缀表示法 中缀表示法:刚才的那个算是就是中缀表示法,我们通常看到的数学符号就是中缀表示法,即数字在计

PAT A1012 The Best Rank

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 ti

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

????????排序的目的就是对一组无序的元素按照一定的次序排列起来.那么总的来说排序要做到事情就只有两件,找到各个元素按照一定次序排列后的位置并把各个元素移动到其所对应的位置.由此看出决定一个排序算法效率的因素也就是这两个: 寻找元素位置所消耗的时间 移动元素到其对应位置所消耗的时间 下面是一些常用的排序算法: 冒泡排序: 算法描述:算法比较简单就不多描述了. 实现步骤: 对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