PATA1080 Graduate Admission

题目链接1080 Graduate Admission
这个题,困扰了我好久,最后发现自己原来是手残,将排序的初值设为了1,应该是0啊!!!!

思路

将所有学生的信息存储下来,包括两个分数ge、gi,以及id,然后按照规则将学生排序。之后遍历已经排好顺序的学生,按照排名来查看当前学生的志愿学校的名额是否已经满了,如果没有满,则将该学生的id加入到该志愿学校的录取名单中,并将该学校的名额减一。如果名额已经满了,则查看该学校最后录取的学生的排名是否与当前学生的排名相同,如果相同,则将当前学生也加入该学校的录取名单。

代码

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <unordered_map>

using namespace std;

struct applicant{
    
    
    int id,ge,gi;
    applicant(){
    
    }
    applicant(int _id,int _ge,int _gi):id(_id),ge(_ge),gi(_gi){
    
    }
    bool operator < (const applicant b){
    
    //重载 < 运算符,自定义结构体排序规则
        if(this->ge + this->gi != b.ge + b.gi)
            return (this->ge + this->gi > b.ge + b.gi);
        else
            return this->ge > b.ge;
    }
};

int n,m,k;
vector<int> quota;//各个学校的名额
vector<applicant> people;//应试者数组
unordered_map<int,int> sequence;//记录学生的排名
unordered_map<int,vector<int>> want;//每个学生的志愿
map<int,vector<int>> ans;//每个学校的录取名单,使用map来存,key有序,本题中无序map也可以

int main()
{
    
    
    scanf("%d%d%d",&n,&m,&k);

    for(int i=0;i<m;i++){
    
    
        int temp;
        scanf("%d",&temp);
        quota.push_back(temp);
    }

    vector<int> cpy(quota);

    for(int i=0;i<n;i++){
    
    
        int id = i;
        int ge,gi;
        scanf("%d%d",&ge,&gi);
        people.push_back(applicant(id,ge,gi));
        for(int j=0;j<k;j++){
    
    
            int temp;
            scanf("%d",&temp);
            want[id].push_back(temp);
        }
    }

    sort(people.begin(),people.end());

    sequence[people[0].id] = 0;//坑了半天!!!!!!!!
    for(int i=1;i<n;i++){
    
    
        if(people[i].ge == people[i-1].ge && people[i].gi == people[i-1].gi)
            sequence[people[i].id] = sequence[people[i-1].id];
        else sequence[people[i].id] = i;
    }

    for(int i=0;i<n;i++){
    
    
        int id = people[i].id;
        for(int j=0;j<k;j++){
    
    
            int cur = want[id][j];
            if(!cpy[cur]) continue;//注意,如果该学生想去的学校本来就不招生,则直接跳过该学校
            if(quota[cur] > 0){
    
    //如果还有名额,则该学生进入学校录取名单
                ans[cur].push_back(id);
                quota[cur]--;//名额减少一个
                break;
            }
            else{
    
    //如果该学校收学生但是名额已经满了
                int lastindex = ans[cur].size()-1;
                int lastid = ans[cur][lastindex];
                if(sequence[lastid] == sequence[id]){
    
    //如果该学生的排名与给学校最后录取的学生排名相同
                    ans[cur].push_back(id);//该学校录取该学生
                    break;
                }
            }
        }
    }

    for(int i=0;i<m;i++){
    
    
        if(!ans[i].size()) printf("\n");
        else{
    
    
            sort(ans[i].begin(),ans[i].end());
            for(int j=0;j<ans[i].size();j++){
    
    
                if(j) printf(" ");
                printf("%d",ans[i][j]);
            }
            printf("\n");
        }
    }

    return 0;
}

坑点:
其实我的思路对了,代码可以通过4个样例,但就是有两个样例通不过,我以为有什么边界数据,但是找不出来。
题目说,排序时,首先看(ge+gi)/2,而ge、gi是用int来存储的,这就是说,如果在结构体applicant中又定义了符合题目要求的一个变量avg,其代表着int 类型的ge、gi的平均数,但是要注意一个问题,就是,因为ge、gi是int型的,如果avg也定义为int类型,则就是整数除法,会只保留整数,举个例子来说,当样例为

2 1 1
1
30 40 0
30 41 0

即有两个应试者,有一个学校收人,每个学生只可以报一个志愿,0号院校的招生名额为1个,这时,看两个应试者的成绩,可以算出来,两人的avg都是35,再看ge成绩,又相同,按照规则这种情况下,0号学校会将两人全部录取。但是其实两人的总分是不同的,只是因为是整数除法,使得得数只保留了整数部分。
而如果,将avg类型修改为double型,又会涉及浮点数比较,无论是在结构体中重载小于运算符还是在遍历数据时,对比当前应试者的avg与目标院校的上一个录取者的avg进行比较时,都涉及浮点数的比较,实在是容易出错。所以,最好是不要计算出avg,而直接使用ge+gi来进行对比。
所以说pat上的数据计算平均数然后进行比较大小的操作时,可以直接使用和来进行比较。
另外,我坑在了一个点上,即排序好的应试者的排名不能取为1,而应该取为0,否则,当people[1]的各项成绩与people[0]的不同时,按照我的写法,这两个数据的排名竟然相同,在这个点上坑了半天。好久没有做排序题了。

猜你喜欢

转载自blog.csdn.net/weixin_44321570/article/details/113666494
今日推荐