例:洛谷P1068 [NOIP2009 普及组]
—分数线划定
题目大意:从一定数量的参加笔试的人中挑出符合面试条件的人,面试的条件是按照成绩从大到小排序,在需要录取的人数的150%处截取,截取的笔试分数就是可以参加面试的条件。(如果截取分数处有好几个人都是这个分数,那么这几个人都可以参加面试)
解题思路
一、考虑数据的存储问题
一个报名参加的选手有两个需要存储的数据:
1.选手的报名号 2.选手的笔试成绩
也就是一个选手有两个用来区分的属性,一般这种情况下就会考虑使用结构体进行存储。
struct voluteer{
int per_num;//选手的报名号
int grade;//选手的笔试成绩
};
二、考虑筛选条件
首先,要取一定数量成绩较高的选手,肯定要将选手按照成绩进行从大到小的排序。其次当两者成绩相同时要满足报名号小的在前。(即:根据结构体的某个属性对结构体的实体进行排序)
普通的sort函数只能对int类型进行从小到大的排序,要对结构体根据其属性进行排序,需要写一个排序算子:
bool compare_g( voluteer a, const voluteer b){
if(a.grade==b.grade) return a.per_num<b.per_num;//选手的成绩相同时将报名号在前的排在前面
return a.grade>b.grade;
}
进行排序之后还没完,我们要找出面试的筛选条件,先根据题目算出选取分数线的排名数,找出分数线之后还没有万事大吉,我们只是找出了分数线,但是题目规定,大于等于这个分数线的选手都可以参加面试,所以我们还需要遍历这个排名数后面的选手,看有没有达到条件的选手,将其也算入总数:
int max_num=m*1.5;//算出截取的排名数
for(int i=max_num+1; i<=n; i++){
if(v[i].grade>=v[max_num].grade) max_num++;//遍历查看截取后的选手中是否还有满足条件的选手
}
至此,此题的主要逻辑部分就已经结束了,下面附上AC代码:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#define maxn 5009
using namespace std;
struct voluteer{
int per_num;
int grade;
};
bool compare_g( voluteer a, const voluteer b){
if(a.grade==b.grade) return a.per_num<b.per_num;
return a.grade>b.grade;
}
int main() {
int n,m;
cin>>n>>m;
voluteer v[maxn];
for(int i=1; i<=n; i++){
cin>>v[i].per_num>>v[i].grade;
}
sort(v+1,v+(n+1),compare_g);
int max_num=m*1.5;
for(int i=max_num+1; i<=n; i++){
if(v[i].grade>=v[max_num].grade) max_num++;
}
cout<<v[max_num].grade<<" "<<max_num<<endl;
for(int i=1; i<=max_num; i++){
cout<<v[i].per_num<<" "<<v[i].grade<<endl;
}
return 0;
}
三、本人遇到的易错点:
- 首先,使用数组时一般会在最大的数据量基础上再加几个存储空间,防止数组溢出。
- 第一次考虑时,我对输入的数据进行了两次排序,第一次先按照报名号从小到大排序,第二次按笔试成绩进行排序。企图达到题目要求的情况,确实,这样排,在有些特殊的情况下是对的,如:在样例中。但是在很多情况下会打乱第一次的排序,导致结果有问题,要避免这种写法。