问题描述
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:
Student _ID C M E
310101 98 85 88
310102 70 95 88
310103 82 87 94
310104 91 91 91
310105 85 90 90
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.
输入格式
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.
输出格式
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.
输入样例
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
(结尾无空行)
输出样例
1 C
1 M
1 E
1 A
3 A
N/A
(结尾无空行)
C语言代码
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
//代表优先级的数组,位置越小,优先级越高,例如 0 代表平均成绩'A'
const char priority[4] = {'A','C','M','E'};
struct Student{
int id;
int grade[4]; //代表 A,C,M,E 四门课的成绩
int rank[4]; //代表该同学 A,C,M,E 四门课的排名
}stu[2010];
//比较函数cmp_X,根据各门课成绩分别进行排序
bool cmp_A(Student a, Student b){
return a.grade[0] > b.grade[0];
}
bool cmp_C(Student a, Student b){
return a.grade[1] > b.grade[1];
}
bool cmp_M(Student a, Student b){
return a.grade[2] > b.grade[2];
}
bool cmp_E(Student a, Student b){
return a.grade[3] > b.grade[3];
}
//根据排序进行排名,注意同分者排名并列
void range(Student s[], int num, int type){
s[0].rank[type] = 1;
for(int i = 1; i < num; i++){
if(s[i].grade[type] == s[i-1].grade[type]){
s[i].rank[type] = s[i-1].rank[type];
}else{
s[i].rank[type] = i + 1;
}
}
}
int main(){
int N, M;
scanf("%d%d", &N, &M);
for(int i = 0; i < N; i++){ //输入并初始化学生信息
scanf("%d%d%d%d", &stu[i].id, &stu[i].grade[1], &stu[i].grade[2], &stu[i].grade[3]);
stu[i].grade[0] = ((stu[i].grade[1] + stu[i].grade[2] + stu[i].grade[3]) * 10 / 3 + 5) / 10; //平均成绩四舍五入
memset(stu[i].rank, 0, sizeof(stu[i].rank)); //将rank[]数组元素初始化为0
}
//根据平均成绩进行排序和排名
sort(stu, stu+N, cmp_A);
range(stu, N, 0);
//根据 C Program Language成绩进行排序和排名
sort(stu, stu+N, cmp_C);
range(stu, N, 1);
根据 Math 成绩进行排序和排名
sort(stu, stu+N, cmp_M);
range(stu, N, 2);
根据 English 成绩进行排序和排名
sort(stu, stu+N, cmp_E);
range(stu, N, 3);
for(int i = 0; i < M; i++){ //输入查找的id
int temp_id;
int j, flag = 0; //flag记录最好排名的科目序号
// int best = stu[j].rank[0]; best记录最好排名,这是初始化的错误做法
scanf("%d", &temp_id);
for(j = 0; j < N; j++){ //找对应id
if(temp_id == stu[j].id){
int best = stu[j].rank[0];
for(int k = 0; k < 4; k++){ //找最好的排名
if(best > stu[j].rank[k]){
best = stu[j].rank[k];
flag = k;
}
}
break;
}
}
if(j == N)
printf("N/A");
else
printf("%d %c", stu[j].rank[flag], priority[flag]);
if(i != M-1)
printf("\n");
}
return 0;
}
编程易错点:
- 审题细节错误。题目中没有明确说明平均分是否需要四舍五入,但根据题目需求,对其要四舍五入处理,保留整数部分即可,可采用 n = ( (n1 + n2 + n3) * 10 / 3 + 5 ) / 10;进行四舍五入处理
- 编程逻辑错误。采用 sort() 函数进行排序之后还要对其进行排名,排名要考虑到并列排名的情况,排名代码如下
stu[0].rank[type] = 1;
for(int i = 1; i < N; i++){
if(stu[i].grade[type] = stu[i-1].grade[type]{
stu[i].grade[type] = stu[i-1].grade[type];
}else{
stu[i].grade[type] = i + 1;
}
}
- 初始化位置不当。对于 best变量的初始化应该在找到对应 id 的学生之后再进行初始化,best 记录的是该同学的最好排名(最靠前的排名),每次查找一个同学之后初始化为该同学的平均成绩排名,直到遇到更靠前的排名,再更新 best 的值,同时记录对应的学科(A、C、M、E)flag
代码优化
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const char priority[4] = {'A','C','M','E'};
int type = 0; //全局变量,0--4 依次代表 'A','C','M','E'
struct Student{
char id[7];
int grade[4];
int rank[4];
}stu[2010];
//比较函数表示比较对应的成绩
bool cmp(Student a, Student b){
return a.grade[type] > b.grade[type];
}
int main(){
int N, M;
scanf("%d%d", &N, &M);
for(int i = 0; i < N; i++){
scanf("%s%d%d%d", stu[i].id, &stu[i].grade[1], &stu[i].grade[2], &stu[i].grade[3]);
stu[i].grade[0] = ((stu[i].grade[1] + stu[i].grade[2] + stu[i].grade[3]) * 10 / 3 + 5) / 10;
memset(stu[i].rank, 0, sizeof(stu[i].rank));
}
//对四个成绩进行排序和排名
for(type = 0; type < 4; type++){
sort(stu, stu+N, cmp);
stu[0].rank[type] = 1;
for(int i = 1; i < N; i++){
if(stu[i].grade[type] == stu[i-1].grade[type]){
stu[i].rank[type] = stu[i-1].rank[type];
}else{
stu[i].rank[type] = i + 1;
}
}
}
for(int i = 0; i < M; i++){ //输入查找的id
char temp_id[7];
int j;
int r = 0; //记录最好排名对应的成绩序号
scanf("%s", temp_id);
for(j = 0; j < N; j++){ //找对应id
if(strcmp(temp_id , stu[j].id)==0){
for(int k = 0; k < 4; k++){ //找最小的排名
if(stu[j].rank[k] < stu[j].rank[r]){
r = k;
}
}
break;
}
}
if(j == N)
printf("N/A");
else
printf("%d %c", stu[j].rank[r], priority[r]);
if(i != M-1)
printf("\n");
}
return 0;
}
优化
- 对 cmp 函数的重复编写用循环表示,设置全局变量 type,表示需要排序的科目和成绩,前提是成绩 grade 和 rank 的元素位置存放对应的都是A,C,M,E
- 减少局部变量best 的使用直接利用对应的位置标记 r ,比较各个排名,找出最好排名