把学生保存为记录,按总分降序、语文降序、学号升序排序后输出前五名。
OJ: luogu
题目 ID: P1093
难度:普及-
标签:排序模拟python
创建: 2026-06-19 01:35
更新: 2026-10-07 10:45
题意
每个学生有语文、数学、英语三科成绩。先计算总分,再按总分高、语文高、学号小的顺序排序,输出前五名的学号和总分。
思路
每个学生保存为:
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 名学生,时间复杂度
总结
排序题最重要的是把关键字顺序写对。降序字段取负,升序字段保持原值,是 Python 多关键字排序的常用写法。