0题目原文(本地存了一份)
原题在洛谷上(页头有链接)。别人的网站不归我们管,打不开、改版、题号调整都可能发生。 所以每个解析页都把题面转录一份存在本地,跟着仓库一起进版本库。
转录自洛谷 P1093,日期见页头。两边不一致时信原站。
题目描述
某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前 $5$ 名学生发奖学金。期末,每个学生都有 $3$ 门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学排在前面。任务:先根据输入的 $3$ 门课的成绩计算总分,然后按上述规则排序,最后按排名顺序输出前五名学生的学号和总分。
输入格式
共 $n+1$ 行。第 $1$ 行为一个正整数 $n$($5 \le n \le 300$)。第 $2$ 到 $n+1$ 行,每行有 $3$ 个用空格隔开的数字,分别表示学号为 $j-1$ 的学生的语文、数学、英语成绩(每个 $0 \sim 100$)。
输出格式
共 $5$ 行,每行两个整数,表示前 $5$ 名学生的学号和总分。
输入输出样例
输入
5 100 90 80 90 90 90 80 80 80 70 70 70 60 60 60
输出
1 270 2 270 3 240 4 210 5 180
这道题考什么:三关键字排序。总分 → 语文 → 学号,每层都是「分得出胜负就 return,分不出就往下一层」。
最容易错的两处
- 总分相同忘了比语文,或者把语文的升降序写反。
- 忘了学号兜底,导致同分同语文时顺序不确定。
能 AC 的:p1093。三层 cmp:总分降序 → 语文降序 → 学号升序,最后只输出前 5。
下面每一步里灰色的「深入」块是折叠的:那是这些结论怎么实测出来的,第一遍可以跳过。
1三层 cmp
#include <bits/stdc++.h>using namespace std;
struct Student { int id; int cn, math, en; int total() const { return cn + math + en; }};
int main() { int n; if (!(cin >> n)) return 0; vector<Student> a(n); for (int i = 0; i < n; i++) { a[i].id = i + 1; cin >> a[i].cn >> a[i].math >> a[i].en; } sort(a.begin(), a.end(), [](const Student &x, const Student &y) { if (x.total() != y.total()) return x.total() > y.total(); if (x.cn != y.cn) return x.cn > y.cn; return x.id < y.id; }); for (int i = 0; i < 5 && i < (int)a.size(); i++) { cout << a[i].id << " " << a[i].total() << "\n"; } return 0;}点「运行 ▶」看结果
if (x.total() != y.total()) return x.total() > y.total();
if (x.cn != y.cn) return x.cn > y.cn;
return x.id < y.id;
⇒ 第 10 章那句「相等就往下一层」,这里走了三层。