当前位置:首页 > 比赛题解 > 2024GESP五级成绩排序(洛谷B3968):C++版多条件排序实战指南

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

3天前比赛题解58

截图未命名.jpg 2024GESP五级成绩排序(洛谷B3968):C++版多条件排序实战指南 GESP五级 成绩排序 多条件排序 C++算法 洛谷B3968 第1张

一、理解题目要求

首先,我们需要清楚地理解题目要求的排序规则:

  1. 总分优先‌:比较三科总分,高者排名靠前

  2. 语文数学总分‌:总分相同时,比较语文和数学两科的总分

  3. 单科最高分‌:如果仍相同,比较语文和数学中的最高分

  4. 并列处理‌:完全相同的成绩则并列,后续名次跳过

二、数据结构设计

我们使用结构体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; // 完全相等时保持原顺序
}

这个函数实现了题目要求的优先级顺序比较,是排序的关键。

四、排名计算技巧

处理并列排名是本问题的难点之一。我们采用以下方法:

  1. 先对排序后的数组进行遍历

  2. 对于每个学生,向后查找所有成绩相同的连续学生

  3. 为这些学生设置相同的排名

  4. 跳过已处理的学生,继续处理下一个不同成绩的学生

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;

六、常见问题与调试技巧

  1. 边界条件‌:注意处理所有学生成绩完全相同的情况

  2. 输入顺序‌:确保最终输出是按原始输入顺序而非排序顺序

  3. 并列处理‌:仔细验证排名是否正确跳过了并列人数


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。