有一段时间没写东西了。
OJ上,评论里都说这是一个水题。事实上,确实也不难。这是NOIP2009普及组的第二题,普及组,第二题,你觉得呢。题目描述摘录如下:
世博会志愿者的选拔工作正在
A
市如火如荼的进行。为了选拔最合适的人才,A
市区对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的150%
划定,即如果计划录取m
名志愿者,则面试分数线为排名第$m\times 150%$(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有选手。
现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。【输入】 输入文件名为
score.in
。
第一行,两个整数n
,m
($5\leq n\leq 5000$,$3\leq m\leq n$),中间用一个空格隔开,其中n表示报名参加笔试的选手总数,m
表示计划录取的志愿者人数。输入数据保证$m\times 150%$向下取整后小于等于n
。第二行到第$n+1$行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号k($1000\leq k\leq 9999$)和该选手的笔试成绩s($1\leq s\leq 100$)。数据保证选手的报名号各不相同。
【输出】 输出文件score.out
。
第一行,有两个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为进入面试的选手的实际人数。
从第二行开始,每行包含两个整数,中间用一个空格隔开,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的顺序输出。
注:成绩达到分数线的都应输出。 解决思路显然很简单:对成绩进行降序排序,同时将报名号作为第二个参数升序排序。代码很容易写出来(为了偷懒,示例代码并不符合C标准,应将其作为C++语言编译):
#include<stdio.h> //标准输入输出头文件
#include<stdlib.h> //标准库,其中声明了qsort()函数
#include<math.h> //数学库,其中声明了floor()函数
typedef struct{
int id; //报名号
int score; //成绩
} volunteer; //依题意,定义一个志愿者结构
int comp(const void *a, const void *b);//声明qsort()需要使用到的比较函数comp()
int main(){
freopen("score.in", "r", stdin);
freopen("score.out", "w", stdout);
volunteer v[5000];//志愿者结构数组
int n, m;
int i;
scanf("%d%d", &n, &m);
for (i = 0; i<n; i++)
scanf("%d%d", &v[i].id, &v[i].score); //读入数据
qsort(v, n, sizeof(volunteer), comp); //排序
/**
*这里是计算分数线
*根据题目所给公式向下取整后,强制类型转换为整型
*数组下标从0开始,故-1
*/
int line = v[((int)floor(m*1.5)) - 1].score;
/**
*此处统计入围面试的实际人数
*从压线志愿者处开始运行循环
*运算次数比较少,效率更加高
*/
for (i = ((int)floor(m*1.5)) - 1; i<n; i++){
if (v[i].score<line){
break; //入围者已全部统计完毕
}
}
int total = i; //将实际人数保存到total中
printf("%d %d\n", line, total); //开始打印答案的第一行
for (i = 0; i<total; i++) //打印后面的志愿者信息
printf("%d %d\n", v[i].id, v[i].score);
return 0;
}
int comp(const void *a, const void *b){
volunteer *c = (volunteer *)a;
volunteer *d = (volunteer *)b;
if (c->score != d->score) //若分数不等,按成绩降序排序
return d->score - c->score;
else //分数相等,按报名号升序排序
return c->id - d->id;
}
代码里的注释应该比较详尽了,再让我多写点也没什么好写的。这份笔记主要就是标记一下比较函数int comp(const void *a,const void *b)
的写法。它的逻辑也不复杂,理解了很快就能记住。