洛谷 B3968 [GESP202403 五级] 成绩排序 题解
题目大意
给定 n n n 个学生的成绩,将这 n n n 个学生的成绩按照题目要求排序后按输入顺序输出他们的排名。
题目分析
这是一道非常典型的自定义排序的题目,最关键的点就在于输出排名的时候要按照输入顺序输出,且存在日常生活中的“并列占位”情况。
对于这道题来说,我们需要一个结构体储存所有学生的信息:
struct student {
int id, c, m, e, total, highest, sum;
/*id为输入顺序,c,m,e含义如题所述,total记录总分,
highest记录语文和数学的最高分,sum记录语文和数学的总分*/
} a[maxn];
下面一个问题,如何排序呢?
库函数能够支持我们自定义排序方法,可以胜任这道题目:
bool cmp(student a, student b) {//排序代码
if (a.total > b.total) return 1;//比较总分
else if (a.total < b.total) return 0;
else {
if (a.sum > b.sum) return 1;//比较语文数学分数和
else if (a.sum < b.sum) return 0;
else {
if (a.highest > b.highest) return 1;//比较语文数学最高分
else if (a.highest < b.highest) return 0;
else return a.id < b.id;
}
}
}
然后就是这道题最关键的部分:如何正确地输出呢?我们不妨用一个 a n s ans ans 数组记录输出的内容。因为这时所有学生的成绩已经是从高往低排序好的,所以我们可以定义一个变量 l a s t last last 记录上一个学生的信息,如果这个学生部分信息和上一个学生部分信息相同,说明他们是并列的:
bool check(int num1, int num2) {//判断是否并列
if (a[num1].total == a[num2].total &&
a[num1].sum == a[num2].sum &&
a[num1].highest == a[num2].highest) return 1;
else return 0;
}
这时候我们就要考虑处理并列的问题了。我们可以定义一个 k k k,代表要额外空出几个位置。每出现一个并列的学生,就将 k k k 累加 1 1 1。需要注意的是,每次用完 k k k 之后,都要把 k k k 清零,否则会出错。
参考代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 10;
struct student {
int id, c, m, e, total, highest, sum;
/*id为输入顺序,c,m,e含义如题所述,total记录总分,
highest记录语文和数学的最高分,sum记录语文和数学的总分*/
} a[maxn];
int n, p = 1;
//p记录用到了第几个位置
int k;
int ans[maxn], last;
bool cmp(student a, student b) {//排序代码
if (a.total > b.total) return 1;//比较总分
else if (a.total < b.total) return 0;
else {
if (a.sum > b.sum) return 1;//比较语文数学分数和
else if (a.sum < b.sum) return 0;
else {
if (a.highest > b.highest) return 1;//比较语文数学最高分
else if (a.highest < b.highest) return 0;
else return a.id < b.id;
}
}
}
bool check(int num1, int num2) {//判断是否并列
if (a[num1].total == a[num2].total &&
a[num1].sum == a[num2].sum &&
a[num1].highest == a[num2].highest) return 1;
else return 0;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].c >> a[i].m >> a[i].e;
a[i].id = i;
a[i].total = a[i].c + a[i].m + a[i].e;
a[i].highest = max(a[i].c, a[i].m);
a[i].sum = a[i].c + a[i].m;
}
sort(a + 1, a + n + 1, cmp);
ans[a[1].id] = 1;
last = 1;
for (int i = 2; i <= n; i++) {
if (check(last, i)) {//有并列的学生
ans[a[i].id] = p;//记录排名
k++;//是并列的学生,累加k
last = i;
continue;
}
p += k + 1;//并列结束,新的占位
k = 0;//记得清空
ans[a[i].id] = p;//记录排名
last = i;//更新缓存信息
}
for (int i = 1; i <= n; i++ ) {
cout << ans[i] << endl;
}
return 0;
}