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

①结构体

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

②排序函数cmp

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

③存放排名的数组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学生的排名

 int Rank[] = {};

④main()

 int main() {
//总计有n个学生,m个查询
scanf("%d%d", &n, &m);
for (int i = ; i < n; i++) {
scanf("%d%d", &stu[i].id, &stu[i].grade);
}
//对n个学生的成绩进行排序
sort(stu, stu + n, cmp);
//第一名的排名为1
Rank[stu[].id] = ;
//剩下学生的排名
for (int i = ; i < n; i++) {
if (stu[i].grade == stu[i - ].grade) {
Rank[stu[i].id] = Rank[stu[i - ].id];
} else {
Rank[stu[i].id] = i + ;
}
}
//m个查询
for (int i = ; i < m; i++) {
scanf("%d", &query);
if (Rank[query] == ) {
printf("N/A\n");
} else {
printf("%d %c\n", Rank[query]);
}
}
return ;
}

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

①结构体修改

 struct Student {
int id;
int grade[];
}stu[];

②排序函数cmp修改

 int now;    //标识当前是A、C、M、E中的哪个科目

 bool cmp(Student a, Student b) {
return a.grade[now] > b.grade[now];
}

③还需要的两个数组

 char course[] = {'A', 'C', 'M', 'E'};    //按优先级排序更方便

 int Rank[][] = {};

④main() : 录入成绩

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

⑤main() : 排名

 for (now = ; now < ; now++) {    //四个科目分别排

     //内部就和单数据排序相同了
sort(stu, stu + n, cmp);
Rank[stu[].id][now] = ;
for (int i = ; i < n; i++) {
if (stu[i].grade[now] == stu[i - ].grade[now]) {
Rank[stu[i].id][now] = Rank[stu[i - ].id][now];
} else {
Rank[stu[i].id][now] = i + ;
}
} }

⑥main() : 查询

 for (int i = ; i < m; i++) {
scanf("%d", &query);
if (Rank[query][] == ) {
printf("N/A\n");
} else {
int k = ;  //因有A>C>M>E的优先级,故这里设初值0
for (int j = ; j < ; j++) {
if (Rank[query][j] < Rank[query][k]) {
k = j;
}
}
printf("%d %c\n", Rank[query][k], course[k]);
}
}

3、题解

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
struct Student {
int id;
int grade[];
}stu[]; char course[] = {'A', 'C', 'M', 'E'};
int Rank[][] = {};
int now; bool cmp(Student a, Student b) {
return a.grade[now] > b.grade[now];
}
int main() {
int n, m, query;
scanf("%d%d", &n, &m);
for (int i = ; i < n; i++) {
scanf("%d%d%d%d", &stu[i].id, &stu[i].grade[], &stu[i].grade[], &stu[i].grade[]);
stu[i].grade[] = round((stu[i].grade[] + stu[i].grade[] + stu[i].grade[]) / 3.0) + 0.5;
}
for (now = ; now < ; now++) {
sort(stu, stu + n, cmp);
Rank[stu[].id][now] = ;
for (int i = ; i < n; i++) {
if (stu[i].grade[now] == stu[i - ].grade[now]) {
Rank[stu[i].id][now] = Rank[stu[i - ].id][now];
} else {
Rank[stu[i].id][now] = i + ;
}
}
}
for (int i = ; i < m; i++) {
scanf("%d", &query);
if (Rank[query][] == ) {
printf("N/A\n");
} else {
int k = ;
for (int j = ; j < ; j++) {
if (Rank[query][j] < Rank[query][k]) {
k = j;
}
}
printf("%d %c\n", Rank[query][k], course[k]);
}
}
return ;
}

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

  1. 【算法学习记录-排序题】【PAT A1016】Phone Bills

    A long-distance telephone company charges its customers by the following rules: Making a long-distan ...

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

    Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of Zhe ...

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

    About 900 years ago, a Chinese philosopher Sima Guang wrote a history book in which he talked about ...

  4. 算法学习记录-排序——插入排序(Insertion Sort)

    插入排序: 在<算法导论>中是这样描述的 这是一个对少量元素进行排序的有效算法.插入排序的工作机理与打牌时候,整理手中的牌做法差不多. 在开始摸牌时,我们的左手是空的,牌面朝下放在桌子上. ...

  5. 算法学习记录-排序——冒泡排序(Bubble Sort)

    冒泡排序应该是最常用的排序方法,我接触的第一个排序算法就是冒泡,老师也经常那这个做例子. 冒泡排序是一种交换排序, 基本思想: 通过两两比较相邻的记录,若反序则交换,知道没有反序的记录为止. 例子: ...

  6. 算法学习记录-排序——选择排序(Simple Selection Sort)

    之前在冒泡排序的附录中提到可以在每次循环时候,不用交换操作,而只需要记录最小值下标,每次循环后交换哨兵与最小值下标的书, 这样可以减少交换操作的时间. 这种方法针对冒泡排序中需要频繁交换数组数字而改进 ...

  7. 算法学习记录-图——应用之拓扑排序(Topological Sort)

    这一篇写有向无环图及其它的应用: 清楚概念: 有向无环图(DAG):一个无环的有向图.通俗的讲就是从一个点沿着有向边出发,无论怎么遍历都不会回到出发点上. 有向无环图是描述一项工程或者系统的进行过程的 ...

  8. 算法学习 拓扑排序(TopSort)

    拓扑排序 一.基本概念 在一个有向无环图(Directed Acyclic Graph, DAG)中,规定< u,v > 表示一条由u指向v的的有向边.要求对所有的节点排序,使得每一条有向 ...

  9. Manacher回文串算法学习记录

    FROM:  http://hi.baidu.com/chenwenwen0210/item/482c84396476f0e02f8ec230 #include<stdio.h> #inc ...

随机推荐

  1. Chocolaty

    原文是用markdown格式写的,稍微改了下发了博客,格式可能会很奇怪.. Chocolaty官网 Chocolaty是一款Windows平台的包管理工具,类似于centos的yum或ubuntu的a ...

  2. thinkphp5.0将数据指模板中

    在控制器中写: public function index(){ $username = \think\Db::table('navigation')->where(array("Vi ...

  3. lvs使用进阶

    之前lvs基础篇(https://www.cnblogs.com/ckh2014/p/10855002.html)中介绍了lvs-dr的搭建,下面我们再复习一下,架构如下: 相关配置 director ...

  4. npm常用模块之mkdirp使用

    更多npm常用模块使用请访问:npm常用模块汇总 mkdirp这是一款在node.js中像mkdir -p一样递归创建目录及其子目录. 更多使用文档请点击访问mkdirp工具官网. 安装 一键安装不多 ...

  5. GYCTFblacklist[堆叠注入 ]

    考点:堆叠注入 handler语句代替select查询 类似于强网杯随便注 不同是过滤了alter,set等函数,不能通过改变列命或着sql预处理查询表内数据 可以使用handler语句代替selec ...

  6. Spring-Cache手动清缓存

    Spring Cache 手动清Redis缓存 注册cacheRedisTemplate 将 cache 的 RedisTemplate 注册为Bean @Bean(name = "cach ...

  7. 求a^b的约数对mod取模

    +; int prime[maxn]; void marktable(int n){ memset(prime,,sizeof(prime)); ;i<=n;i++){ ]]=i; ;j< ...

  8. Vuejs开发环境的搭建

    Windows系统上搭建VueJS开发环境 1.安装node.js:在node.js官网下载对应系统的msi包并安装 注:node的安装分全局和本地模式.一般情况下会以本地模式运行,包会被安装到和你的 ...

  9. shell脚本执行sql命令

    参考:https://www.cnblogs.com/xingchong/p/11698237.html

  10. 解决jquery click事件执行两次

    js 解决办法 event.preventDefault() :阻止默认行为,可以用 event.isDefaultPrevented() 来确定preventDefault是否被调用过了 event ...