CSU CS 数据结构练习题 P1068 题解
题目信息
题目链接:https://www.luogu.com.cn/problem/P1068
知识点:模拟、排序(多关键字的数据排序)
题目简述
\(n\) 位选手前来笔试,第 \(i\) 位选手的报名号为 \(k_i\),成绩为 \(s_i\),保证所有人报名号各不相同。计划录取 \(m\) 人,设定面试分数线为排名第 \(\left\lfloor m\times 150\%\right\rfloor\) 名的选手的分数,成绩不低于面试分数线的所有人可进入面试。
基于上述规则,请你输出面试分数线,并按降序输出录取的所有人的考号和分数。按照笔试成绩从高到低输出,若成绩相同,则按报名号由小到大的顺序输出。
\(5\le n\le 5000, 3\le m\le n, 1000\le k_i\le 9999, 1\le s_i\le 100\)。
1S,125MB。
题目分析
详细版
题目要求输出面试分数线、实际录取的总人数与录取的所有选手的信息。然而显然面试分数线与录取人数需要根据排序后的成绩确定。因此本题重点在于如何将所有选手按照成绩与报名号排序。
那么最核心的问题是一个多关键字排序问题,对所有选手排序时,要求以成绩降序为第一关键字,以报名号升序为第二关键字。得到排序结果后,即可直接得到排名第 \(\left\lfloor m\times 150\%\right\rfloor\) 名的选手的分数,也即面试分数线,然后按顺序输出所有比分数线高的选手信息即可。
基于上述算法流程,考虑选择数据结构与算法:
- 因为是多关键字排序,对于每个选手有报名号与成绩两个属性,因此将每个选手的信息构造成一个结构体最合适;
- 本题 \(n\le 5000\),时限 1S,允许时间复杂度 \(O(n^2)\) 的算法通过,可以任意选择一个排序算法实现;
- 为了方便运行排序算法,考试使用数组存储所有选手的信息构成的序列;
- 因为使用了结构体,为了方便实现,考虑选择一种基于比较的排序方式,这里我们选择插入排序作为排序算法。
基于选择的上述数据结构与算法,进一步细化具体的程序实现:
- 输入选手的信息,构造初始的结构体序列;
- 运行选择排序,每次选择成绩最高的选手,若分数相同则选择报名号最小的选手,将其放到有序部分的最后;
- 计算得到分数线并输出;
- 最后按顺序枚举并输出所有比分数线高的选手信息即可。
排序时间复杂度 \(O(n^2)\) 级别,输入与输出时间复杂度 \(O(n)\) 级别。则显然的,总时间复杂度 \(O(n^2)\) 级别,空间复杂度 \(O(n)\) 级别。
省流版
发现分数线要根据排序结果确定,考虑先排序。排序后得到分数线,然后按排序结果输出所有过线的人即可。
排序规则是一个显然的多关键字排序,考虑使用结构体存元素信息;又数据范围较小,于是任意选择一个基于比较的排序算法实现即可。
使用选择排序实现,总时间复杂度 \(O(n^2)\) 级别,空间复杂度 \(O(n)\) 级别,可以通过本题。
代码实现

//P1068 [NOIP 2009 普及组] 分数线划定
/*
链接:https://www.luogu.com.cn/problem/P1068
知识点:模拟、排序(多关键字的数据排序)
*/
#include <stdio.h>
#include <math.h>
//=============================================================
int n, m;
struct Competitor {
int k, s;
} a[5010];
//=============================================================
void SortCompetitor(int L_, int R_) {
for (int i = L_; i <= R_; ++ i) {
int p = i, temp;
for (int j = i + 1; j <= R_; ++ j) {
if ((a[j].s > a[p].s) || (a[j].s == a[p].s && a[j].k < a[p].k) ) {
p = j;
}
}
temp = a[i].k, a[i].k = a[p].k, a[p].k = temp;
temp = a[i].s, a[i].s = a[p].s, a[p].s = temp;
}
}
//=============================================================
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++ i) {
scanf("%d%d", &a[i].k, &a[i].s);
}
SortCompetitor(1, n);
int pos = floor(1.5 * m), cnt = 1;
while (cnt + 1 <= n && a[cnt + 1].s >= a[pos].s) {
++ cnt;
}
printf("%d %d\n", a[pos].s, cnt);
for (int i = 1; i <= cnt; ++ i) printf("%d %d\n", a[i].k, a[i].s);
return 0;
}

浙公网安备 33010602011771号