2024GESP五级成绩排序(洛谷B3968):C++版多条件排序实战指南

一、理解题目要求
首先,我们需要清楚地理解题目要求的排序规则:
总分优先:比较三科总分,高者排名靠前
语文数学总分:总分相同时,比较语文和数学两科的总分
单科最高分:如果仍相同,比较语文和数学中的最高分
并列处理:完全相同的成绩则并列,后续名次跳过
二、数据结构设计
我们使用结构体Student来存储每个学生的信息:
struct Student {
int id; // 原始输入顺序
int chinese; // 语文成绩
int math; // 数学成绩
int english; // 英语成绩
int total; // 三科总分
int cm_sum; // 语文+数学总分
int cm_max; // 语文和数学中的最高分
int rank; // 最终排名
};这种设计将所有相关信息集中存储,便于后续处理和排序。
三、自定义排序函数
核心在于自定义比较函数compare:
bool compare(const Student &a, const Student &b) {
if (a.total != b.total) return a.total > b.total;
if (a.cm_sum != b.cm_sum) return a.cm_sum > b.cm_sum;
if (a.cm_max != b.cm_max) return a.cm_max > b.cm_max;
return false; // 完全相等时保持原顺序
}这个函数实现了题目要求的优先级顺序比较,是排序的关键。
四、排名计算技巧
处理并列排名是本问题的难点之一。我们采用以下方法:
先对排序后的数组进行遍历
对于每个学生,向后查找所有成绩相同的连续学生
为这些学生设置相同的排名
跳过已处理的学生,继续处理下一个不同成绩的学生
for (int i = 0; i < n; ) {
int j = i;
while (j < n && !compare(sorted[i], sorted[j]) && !compare(sorted[j], sorted[i])) {
++j;
}
for (int k = i; k < j; ++k) {
sorted[k].rank = i + 1;
}
i = j;
}五、完整代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 学生结构体,存储原始数据和计算后的各种分数
struct Student {
int id; // 原始输入顺序
int chinese; // 语文成绩
int math; // 数学成绩
int english; // 英语成绩
int total; // 三科总分
int cm_sum; // 语文+数学总分
int cm_max; // 语文和数学中的最高分
int rank; // 最终排名
};
// 自定义比较函数,用于排序
bool compare(const Student &a, const Student &b) {
if (a.total != b.total) return a.total > b.total;
if (a.cm_sum != b.cm_sum) return a.cm_sum > b.cm_sum;
if (a.cm_max != b.cm_max) return a.cm_max > b.cm_max;
return false; // 完全相等时保持原顺序
}
int main() {
int n;
cin >> n;
vector<Student> students(n);
// 读取输入数据并计算各种分数
for (int i = 0; i < n; ++i) {
cin >> students[i].chinese >> students[i].math >> students[i].english;
students[i].id = i;
students[i].total = students[i].chinese + students[i].math + students[i].english;
students[i].cm_sum = students[i].chinese + students[i].math;
students[i].cm_max = max(students[i].chinese, students[i].math);
}
// 复制一份用于排序
vector<Student> sorted = students;
sort(sorted.begin(), sorted.end(), compare);
// 计算排名,处理并列情况
for (int i = 0; i < n; ) {
int j = i;
// 找到所有与当前学生成绩相同的连续学生
while (j < n && !compare(sorted[i], sorted[j]) && !compare(sorted[j], sorted[i])) {
++j;
}
// 为这些学生设置相同的排名
for (int k = i; k < j; ++k) {
sorted[k].rank = i + 1;
}
i = j;
}
// 将排名信息映射回原始顺序
vector<int> original_order_rank(n);
for (int i = 0; i < n; ++i) {
original_order_rank[sorted[i].id] = sorted[i].rank;
}
// 按原始输入顺序输出排名
for (int i = 0; i < n; ++i) {
cout << original_order_rank[i] << endl;
}
return 0;六、常见问题与调试技巧
边界条件:注意处理所有学生成绩完全相同的情况
输入顺序:确保最终输出是按原始输入顺序而非排序顺序
并列处理:仔细验证排名是否正确跳过了并列人数
原创内容 转载请注明出处
