C语言应用实例:奋勇争先锋(贪心,qsort用法)
一、题目
还记得上次那个奋勇争先的题目吗,聪明的你帮助老师找出了第一名的同学。
现在,有个类似的问题:
已知每一位同学的解题数量和罚时,这次希望你能输出排名靠前的若干同学的名单。
注:排名首先依据做题数量,若做题数量相同,则比较罚时,罚时少的排名靠前。
要求:
第一行是数据组数C,代表有C组测试实例。
每一组数据第一行两个整数N和M,N代表有N个人的成绩,M表示老师需要你输出前M名的名单。
接下来N行,每一行依次给出名字Name,做出的题目数量num和罚时time
( 1<=C<=10, 2<M<=N<=1000, Name的长度最大为10,1<=num<=10, 10<=time<=100000 )
每组测试数据输出M行,第i行为第i名的名字、解题数量和罚时,中间用空格隔开。
每组数据后空一行
二、题解
1.思路
这道题的难点在于结构体的双重排序(结构体的定义前面已经讲过了这里就不多赘叙了)
主包在第一次看到这个题的时候的想法是用两边qsort函数
如下
int compare1(const void *a,const void *b){struct Stu *m1 = (struct Stu*)a;struct Stu *m2 = (struct Stu*)b;if(m1->num > m2->num) return -1;if(m1->num < m2->num) return 1;
}int compare2(const void *a,const void *b){struct Stu *m1 = (struct Stu*)a;struct Stu *m2 = (struct Stu*)b;if(m1->num == m2->num&&m1->time>m2->time) return 1;if(m1->num == m2->num&&m1->time<m2->time) return -1;
}int main(){
qsort(stulist,N,sizeof(struct Stu),compare1);qsort(stulist,N,sizeof(struct Stu),compare2);
return 0;
}但这样写的话第二次排序会覆盖住第一次排序的结果,所以不能这么写
正确处理写法如下(调用一遍qsort)
int compare(const void *a, const void *b){struct Stu *m1 = (struct Stu*)a;struct Stu *m2 = (struct Stu*)b;// 首先按num降序排序if(m1->num != m2->num){return m2->num - m1->num; // 降序}// 如果num相同,按time升序排序else{return m1->time - m2->time; // 升序}
}最后输出前N就行
2.完整代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>struct Stu{char name[11];int num;int time;
};int compare(const void *a, const void *b){struct Stu *m1 = (struct Stu*)a;struct Stu *m2 = (struct Stu*)b;// 首先按num降序排序if(m1->num != m2->num){return m2->num - m1->num; // 降序}// 如果num相同,按time升序排序else{return m1->time - m2->time; // 升序}
}int main(){int C;scanf("%d",&C);for(int i=0;i<C;i++){int N,M;scanf("%d %d",&N,&M);struct Stu *stulist=(struct Stu*)malloc(sizeof(struct Stu)*N);for(int j=0;j<N;j++){scanf("%s %d %d", stulist[j].name, &stulist[j].num, &stulist[j].time);}qsort(stulist, N, sizeof(struct Stu), compare);for(int j=0;j<M;j++){printf("%s %d %d\n", stulist[j].name, stulist[j].num, stulist[j].time);}printf("\n");free(stulist);}return 0;
}