结构体排序问题

例:洛谷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;
}

三、本人遇到的易错点:
  • 首先,使用数组时一般会在最大的数据量基础上再加几个存储空间,防止数组溢出。
  • 第一次考虑时,我对输入的数据进行了两次排序,第一次先按照报名号从小到大排序,第二次按笔试成绩进行排序。企图达到题目要求的情况,确实,这样排,在有些特殊的情况下是对的,如:在样例中。但是在很多情况下会打乱第一次的排序,导致结果有问题,要避免这种写法。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值