MENU

笔记:使用qsort进行多字段排序

February 28, 2014 • 程序阅读设置

有一段时间没写东西了。

OJ上,评论里都说这是一个水题。事实上,确实也不难。这是NOIP2009普及组的第二题,普及组,第二题,你觉得呢。题目描述摘录如下:

世博会志愿者的选拔工作正在A市如火如荼的进行。为了选拔最合适的人才,A市区对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的150%划定,即如果计划录取m名志愿者,则面试分数线为排名第$m\times 150%$(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有选手。
现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。

【输入】 输入文件名为score.in
第一行,两个整数nm($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)的写法。它的逻辑也不复杂,理解了很快就能记住。

Archives Tip
QR Code for this page
Tipping QR Code