PAT 1012 The Best Rank (25分) sort()排序就完了

Scroll Down

题目

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个学生的信息(IDC课成绩、M课成绩、E课成绩),计算学生的四个排名(均分A排名、C课排名、M课排名、E课排名),并选出最好的排名(按照优先级 A > C > M > E);分数相同就并列排名;

给出M次查询,每次的输入是一个学生ID,如果这个学生不存在(或者说录入的信息中没有他)就输出 N/A,否则就输出它最好的排名,及这个排名是根据哪一项排的。

思路分析

  • 用结构体 Student 保存学生信息,注意我们保存排名的数组rank[]就按照优先级ACME的顺序去存,这样我们在选择最好的排名的时候,就可以从左到右遍历这个数组选择最小的那个,就是满足优先级高低的最好排名。
	struct Student {
	    int id; // 6位的id
	    int score[4], rank[4]; // 四个成绩,及按这个成绩的排名 A C M E,注意顺序,按优先级保存,之后判断最好的排名会容易
	    int best_rank_index;// 最好的排名对应的是哪一项排名
	}stu[2000];
  • 在读入学生信息的时候,计算出他的平均成绩(记得四舍五入,最后保存的还是int
  • 分别用四个成绩(ACME,score[0]-score[3])字段作为判断标准,对结构体数组执行sort(stu, stu+n, cmp)进行排序,cmp是我们自己实现的比较函数,我们可以这样写这个函数,然后只需要在每次排序前改变flag就可以不用写四个比较函数。
	bool cmp(Student a, Student b) {return a.score[flag] > b.score[flag];}

每次排完序后,将对应科目的排名写进每个学生对应的rank[flag]中(记得判断和他前一个同学的成绩,如果相同要并列)

  • 最后一次排名结束后,对每个学生都要找出他最好的排名是哪个排名,保存在best_rank_index
  • 每一个学生都有一个ID,用一个数组exist[]来保存学生是否存在,以他的ID做索引,如果他存在,就把值设置为最后一次排名后他在stu数组中的下标+1,这样有两个好处:一个是之后查询时,如果exit[id]==0就说明他不存在;而是如果他存在那么exit[id]-1就是他在stu数组中的位置,这样我们能很快找到他并输出他的最好排名。

完整代码

注释我写的很详细了,结合注释很多地方都能看的很明白。

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

/**
 * 现已知n个考生的3门分数,平均分可以按照这三门(C M E)算出来。
 * 然后分别对这四个分数从高到低排序,这样对每个考生来说有4个排名。
 * k个查询,对于每一个学生id,输出当前id学生的最好的排名和它对应的科目,
 * 如果名次相同,按照A>C>M>E优先级输出最好的排名及其对应的那个指标~如果当前id不存在,输出N/A~
 */ 
// 保存学生信息
struct Student {
    int id; // 6位的id
    int score[4], rank[4]; // 四个成绩,及按这个成绩的排名 A C M E,注意顺序,按优先级保存,之后判断最好的排名会容易
    int best_rank_index;// 最好的排名对应的是哪一项排名
}stu[2000];

// 学号6位数,最多有 999999 个,
int exist[1000000] = {0};

// 用哪个成绩排名
int flag;

// 用于降序排序
bool cmp(Student a, Student b) {return a.score[flag] > b.score[flag];}

int main() {

    // n个学生,m个学生要查排名
    int n, m;
    cin >> n >> m;
    // 录入n个学生成绩信息
    for (int i = 0; i < n; ++i){
        // ID A C M E
        cin >> stu[i].id >> stu[i].score[1] >> stu[i].score[2] >> stu[i].score[3];
        // 计算 A 四舍五入
        stu[i].score[0] = round((stu[i].score[1] + stu[i].score[2] + stu[i].score[3]) / 3.0);
    }
    // 分别按照四个成绩进行排名
    for (flag = 0; flag <= 3; ++flag) {
        // 根据这一项成绩排名
        sort(stu, stu + n, cmp);
        // 把根据这一分数的排名结果存进stu.rank[4]对应的那一栏
        for (int j = 0; j < n; ++j) {
            // 这一项分数相同就并列,从i = 1开始要判断这个
            if (j == 0 || stu[j].score[flag] != stu[j - 1].score[flag])
                stu[j].rank[flag] = j + 1;
            else // 并列
                stu[j].rank[flag] = stu[j - 1].rank[flag];
        }
    }

    // 找到每个学生最好的排名项,并填到stu.betRankIndex,
    for (int i = 0; i < n; ++i){
        stu[i].best_rank_index = 0;
        for (flag = 1; flag <= 3; ++flag) {
            if (stu[i].rank[flag] < stu[i].rank[stu[i].best_rank_index])
                stu[i].best_rank_index = flag;
        }
        // 并把这个学生在数组中的位置+1作为他存在与否的标志
        // 因为数组初始化为0,而stu[]数组下标从0开始,所以赋值成下标+1才可以区分这个学生是不是存在
        // 另一方面,等会要查询指定学号的学生排名时,能根据exist[学号]-1得到他在stu[]中的位置,很快定位
        exist[stu[i].id] = i + 1;
    }
    // 读取要查看排名的m个学生学号
    int id;
    char c[5] = {'A', 'C', 'M', 'E'};
    for (int i = 0; i < m; ++i){
        cin >> id;
        // 学生不存在
        if (exist[id] == 0)
            cout << "N/A" << endl;
        else {
            // 他在stu[]中的下标
            int index = exist[id] - 1;
            // 他最好的排名是哪一项
            int best_rank_index = stu[index].best_rank_index;
            // 输出他最好的排名和对应的那个科目
            cout << stu[index].rank[best_rank_index] << " " << c[best_rank_index] << endl;
        }
            
    }

    return 0;
}