c++之洛谷P1068分数线划定

这是个排序题,做题过程中对sort的理解加深了不少,记下来避免忘记。

题目来源:https://www.luogu.org/problemnew/show/P1068

题目描述

世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,AA市对

所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根

据计划录取人数的150\%150%划定,即如果计划录取mm名志愿者,则面试分数线为排名第m \times 150\%m×150%

(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有

选手。

现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成

绩。

输入输出格式

输入格式:

第一行,两个整数 n,m(5 ≤ n ≤ 5000,3 ≤ m ≤ n)n,m(5≤n≤5000,3≤m≤n),中间用一个空格隔开,其

中nn表示报名参加笔试的选手总数,mm表示计划录取的志愿者人数。输入数据保证 m \times 150\%m×150%

向下取整后小于等于 nn。

第二行到第 n+1n+1 行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号 k(1000 ≤ k ≤ 9999)k(1000≤k≤9999)和该选手的笔试成绩s(1 ≤ s ≤ 100)s(1≤s≤100)。数据保证选手的报名号各不相同。

输出格式:

第一行,有22个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为进入面试的选手的实际人数。

从第二行开始,每行包含22个整数,中间用一个空格隔开,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的顺序输出。

输入示例:

6 3

1000 90

3239 88

2390 95

7231 84

1005 95

1001 88

输出:

88 5

1005 95

2390 95

1000 90

1001 88

3239 88

分析:结构体定义,分数排序,确定分数线,确定实际大于等于分数线的人数,考号排序,输出。

后来发现可以直接将分数排序和考号排序合成一体,减少了好几行代码。

初次代码思路:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <math.h>
 4 using namespace std;
 5 struct Can {
 6     int num;
 7     int score;
 8 }can[5001];
 9 bool compare1(Can a, Can b)
10 {
11     return a.score > b.score;
12 }
13 bool compare2(Can a, Can b)
14 {
15     return a.num < b.num;
16 }
17 int n, m;
18 int mline, mscore;
19 int head = 0, tail = 1, mid;
20 int main()
21 {
22     cin >> n >> m;
23     for (int i = 0; i < n; i++) cin >> can[i].num >> can[i].score;
24     sort(can, can + n, compare1);
25     mline = floor(1.5*m);
26     mscore = can[mline - 1].score;
27     for (int i = floor(1.5*m); i < n; i++)
28         if (can[i].score == mscore)
29             mline++;
30     mid = can[0].score;
31     for (int i = 1; i <= mline; i++)
32     {
33         if (can[i].score != mid)
34         {
35             sort(can + head, can + tail + head, compare2);
36             head = head + tail;
37             tail = 1;
38             mid = can[head].score;
39         }
40         else tail++;
41     }
42     cout << mscore << " " << mline << endl;
43     for (int i = 0; i < mline; i++)
44         cout << can[i].num << " " << can[i].score << endl;
45     return 0;
46 }

备忘录1:结构体排序

 1 bool compare(example x, example y)
 2 {  
 3 return x.a<y.a;
 4 //<升序,>降序
 5 }
 6 
 7 struct example
 8 {
 9 int a,b;
10 }ex[n];
11 
12 sort(ex, ex+n, compare);

即可对ex[n]中的a部分进行升序排序,其他部分(b)随动。

若要将分数排序和考号排序合成一体,可用如下代码:

 1 struct Can {
 2     int num;
 3     int score;
 4 }can[5001];
 5 int cmp(Can a, Can b){
 6     if(a.score>b.score){
 7                     //比成绩
 8         return true;
 9     }
10     else if(a.score==b.score){
11         if(a.num<b.num)return true;
12                     //比较考号
13         else return false;
14     }
15     else return false;
16 }      

减少了31-40行的10行代码,还减少了出错的可能性。

备忘录2:部分排序

一般用到排序时我们是这样用的:

1 int p[n]; 2 sort(p,p+n,compare);

从p数组的开头开始,进行长度为n的排序。

那么,不从p的开头开始而是从其中间开始的排序应该怎么写呢?

1 sort(p+a,p+b,compare);

其中a为开始排序的下标,b-1为结束排序的下标。

例:

1 int p[7]={9,8,7,6,5,4,3};
2 sort(p+1,,p+7);//结果{9,3,4,5,6,7,8}
3 sort(p+1,p+6);//结果{9,4,5,6,7,8,3}
4 sort(p+2,p+4);//结果{9,8,6,7,5,4,3}

也就是说b-a就是排序的长度。