题单 · 习题解析

洛谷 B2159 成绩排序

成绩从高到低,同分名字字典序小的在前 —— 最简单的多关键字 cmp

原题:洛谷 B2159出自 第 10 章 排序:冒泡 → 归并 → 快排 的题单题面本地存档:2026-10-18
⚠ 先自己写一遍,再往下看

这一页不是标准答案,是一条阶梯:把大多数人真实会写出的第一版摆出来, 看它错在哪、慢在哪,再一步一步改。所以它对「已经自己动手撞过一次墙」的人最有用。
还没写过的话,先去写 —— 写出来的哪怕是错的,也比直接看这一页收获大。

0题目原文(本地存了一份)

为什么要在这儿抄一份题面

原题在洛谷上(页头有链接)。别人的网站不归我们管,打不开、改版、题号调整都可能发生。 所以每个解析页都把题面转录一份存在本地,跟着仓库一起进版本库。

转录自洛谷 B2159,日期见页头。两边不一致时信原站。

题目描述

给出班里某门课程的成绩单,请你按成绩从高到低对成绩单排序输出,如果有相同分数则名字字典序小的在前。

输入格式

第一行为 $n$($0 < n < 20$),表示班里的学生数目;接下来的 $n$ 行,每行为每个学生的名字和他的成绩,中间用单个空格隔开。名字只包含字母且长度不超过 $20$,成绩为一个不大于 $100$ 的非负整数。

输出格式

把成绩单按分数从高到低的顺序进行排序并输出,每行包含名字和分数两项,之间有一个空格。

输入输出样例

输入

3
Alice 90
Bob 85
Charlie 90

输出

Alice 90
Charlie 90
Bob 85
学生版:一页看懂这道题

这道题考什么:多关键字排序的最小版本 —— 先按分数从高到低,分数相同按名字字典序从小到大。

最容易错的两处

  1. 把「分数高的在前」写成 return x.score < y.score;,顺序就反了。
  2. 同分时忘了比名字,或者把名字的比较写反。

能 AC 的:b2159。cmp 里先比分数(降序),分不出高下再比名字(升序)。

下面每一步里灰色的「深入」块是折叠的:那是这些结论怎么实测出来的,第一遍可以跳过。

1直接按 cmp 排

b2159.cpp★ 这一版就能 AC
#include <bits/stdc++.h>
using namespace std;
struct Student {
string name;
int score;
};
int main() {
int n;
if (!(cin >> n)) return 0;
vector<Student> a(n);
for (int i = 0; i < n; i++) cin >> a[i].name >> a[i].score;
sort(a.begin(), a.end(), [](const Student &x, const Student &y) {
if (x.score != y.score) return x.score > y.score;
return x.name < y.name;
});
for (auto &s : a) cout << s.name << " " << s.score << "\n";
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
★ 两行 cmp 就是全部

if (x.score != y.score) return x.score > y.score; —— 分数高的在前。

return x.name < y.name; —— 分数相同,名字字典序小的在前。

⇒ 和第 10 章那句「先分主次,主的分不出高下再看次的」是同一件事。