题意

每个学生有语文、数学、英语三科成绩。先计算总分,再按总分高、语文高、学号小的顺序排序,输出前五名的学号和总分。

思路

每个学生保存为:

python
(student_id, total, chinese)

排序规则可以直接写成 key 元组:

python
(-total, -chinese, student_id)

总分和语文要降序,所以加负号;学号要升序,直接使用原值。

Python 知识

  • /home/rainboy/mycode/hugo-blog/content/program_language/python/sorting_and_ordering.md:多关键字排序可以用元组 key。
  • /home/rainboy/mycode/hugo-blog/content/program_language/python/input_output_and_strings.md:每行三个整数用 map(int, input().split())。
  • students[:5] 取排序后的前五名。

代码

python
n = int(input())
students = []

for student_id in range(1, n + 1):
    chinese, math, english = map(int, input().split())
    total = chinese + math + english
    students.append((student_id, total, chinese))

students.sort(key=lambda student: (-student[1], -student[2], student[0]))

for student in students[:5]:
    print(student[0], student[1])

Pythonic 写法

多关键字 sort:

python
n = int(input())
students = []
for sid in range(1, n + 1):
    c, m, e = map(int, input().split())
    students.append((- (c + m + e), -c, sid, c + m + e))
for _, _, sid, total in sorted(students)[:5]:
    print(sid, total)

STL 写法

把排序规则写成函数对象:结构体 StudentCmp 重载 operator(),回答“第一个学生是否应该排在第二个前面”。把它交给 sort 后,总分降序、语文降序、学号升序三条要求逐条落进 operator() 的分支,排序结果唯一确定。和上面 Python 用 key 元组加负号的写法相比,这里的分支更像是在逐条翻译题目里的排序规则。

对应的 cppbook 章节:比较规则与函数对象

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-07 01:42
 * update_at: 2026-10-07 01:48
 */
// 这是 STL 写法:用函数对象(重载 operator() 的结构体)作为 sort 的比较规则。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MAXN = 305;

// 一名学生的记录:学号、语文成绩、三科总分。
struct Student {
    ll id;       // 学号,按输入顺序从 1 开始
    ll chinese;  // 语文成绩
    ll total;    // 语文 + 数学 + 英语
};

// 比较规则(函数对象):总分降序 -> 语文降序 -> 学号升序。
// operator() 回答的问题是“a 是否应该排在 b 前面”。
// 三个分支覆盖了题目给出的排序要求,且不会出现 cmp(a, b) 与 cmp(b, a) 同时为真。
struct StudentCmp {
    bool operator()(const Student &a, const Student &b) const {
        if (a.total != b.total) {
            return a.total > b.total;
        }
        if (a.chinese != b.chinese) {
            return a.chinese > b.chinese;
        }
        return a.id < b.id;
    }
};

ll n;
Student stu[MAXN]; // stu[i] 表示第 i 个输入的学生,下标从 1 开始

void read_input() {
    cin >> n;
    for (ll i = 1; i <= n; i++) {
        ll chinese, math, english;
        cin >> chinese >> math >> english;
        stu[i].id = i;
        stu[i].chinese = chinese;
        stu[i].total = chinese + math + english;
    }
}

void solve() {
    // 把写好的函数对象交给 sort,作为“谁排在前面”的规则。
    sort(stu + 1, stu + n + 1, StudentCmp());

    ll limit = min(n, 5LL);
    for (ll i = 1; i <= limit; i++) {
        cout << stu[i].id << ' ' << stu[i].total << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    read_input();
    solve();

    return 0;
}

复杂度

排序 n 名学生,时间复杂度 O(nlog⁡n)O(n\log n),空间复杂度 O(n)O(n)。

总结

排序题最重要的是把关键字顺序写对。降序字段取负,升序字段保持原值,是 Python 多关键字排序的常用写法。