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\) 名的选手的分数,也即面试分数线,然后按顺序输出所有比分数线高的选手信息即可。

基于上述算法流程,考虑选择数据结构与算法:

  1. 因为是多关键字排序,对于每个选手有报名号与成绩两个属性,因此将每个选手的信息构造成一个结构体最合适;
  2. 本题 \(n\le 5000\),时限 1S,允许时间复杂度 \(O(n^2)\) 的算法通过,可以任意选择一个排序算法实现;
  3. 为了方便运行排序算法,考试使用数组存储所有选手的信息构成的序列;
  4. 因为使用了结构体,为了方便实现,考虑选择一种基于比较的排序方式,这里我们选择插入排序作为排序算法。

基于选择的上述数据结构与算法,进一步细化具体的程序实现:

  1. 输入选手的信息,构造初始的结构体序列;
  2. 运行选择排序,每次选择成绩最高的选手,若分数相同则选择报名号最小的选手,将其放到有序部分的最后;
  3. 计算得到分数线并输出;
  4. 最后按顺序枚举并输出所有比分数线高的选手信息即可。

排序时间复杂度 \(O(n^2)\) 级别,输入与输出时间复杂度 \(O(n)\) 级别。则显然的,总时间复杂度 \(O(n^2)\) 级别,空间复杂度 \(O(n)\) 级别。

省流版

发现分数线要根据排序结果确定,考虑先排序。排序后得到分数线,然后按排序结果输出所有过线的人即可。

排序规则是一个显然的多关键字排序,考虑使用结构体存元素信息;又数据范围较小,于是任意选择一个基于比较的排序算法实现即可。

使用选择排序实现,总时间复杂度 \(O(n^2)\) 级别,空间复杂度 \(O(n)\) 级别,可以通过本题。

代码实现

附件 6 题目通过记录截图示例

//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;
}
posted @ 2026-03-08 14:11  Rainycolor  阅读(141)  评论(0)    收藏  举报