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;
六、常见问题与调试技巧
边界条件:注意处理所有学生成绩完全相同的情况
输入顺序:确保最终输出是按原始输入顺序而非排序顺序
并列处理:仔细验证排名是否正确跳过了并列人数
原创内容 转载请注明出处