PAT甲级 1080 Graduate Admission(30)


题目

原题链接

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题目大意

每个申请人都必须提供两个成绩:全国入学考试成绩GE和面试成绩GI,申请人的最终成绩是 (GE+GI) / 2。

录取规则:

  • 申请者将根据其最终成绩由高到低进行排名,并且将从排名列表的顶部开始逐一录取。
  • 如果申请者的最终成绩并列,则按照 GE 成绩由高到低进行排名,如果成绩仍然并列,则并列者的排名必须相同
  • 每个申请人可以填报 K 个志愿,并且将根据他/她的志愿进行录取:如果按照排名列表,轮到某位学生被录取了,并且其第一志愿学校还未招满人,则他成功被该学校录取。如果名额已满,则按顺序考虑其他志愿,直至成功被录取为止。如果所有报名学校都无法录取该名学生,则该名学生录取失败。
  • 如果出现并列排名,并且并列申请人正在申请同一所学校,那么该学校不得只录取其中一部分申请人,即使超过招生限额,也必须全部录取

输入格式
第一行包含三个整数,N 表示总申请人数量,M 表示学校数量,K 表示可填报志愿数量。
第二行包含 M 个整数,表示每所学校的计划招生人数。
接下来 N 行,每行包含 2+K 个整数,前两个整数表示一名申请人的GE和GI,接下来K个整数,表示该申请人的志愿学校编号。
所有学校编号 0∼M−1,所有申请人编号 0∼N−1。

输出格式
输出所有研究生院的录取结果。
每所学校的录取结果占据一行,其中包含所有学校录取的申请人的编号。编号必须按升序排列,并用空格分隔。
每行的末尾必须没有多余的空格。
如果某学校没有录取任何学生,则必须相应地输出空白行。

数据范围
1≤N≤40000,1≤M≤100,1≤K≤5,0≤GE,GI≤100,每所学校的计划招生人数不会超过 2000。

基本思路

首先创建一个申请人结点结构Node,里面存储了申请人的志愿学校编号(使用vector来存储),入学考试成绩ge,面试成绩gi,总成绩score,申请人的编号val。再创建一个结构体数组node,存储每个申请人的结点。

struct Node {
   
   
    vector<int> vc;// 存储每个学生的志愿学校编号
    int ge;// 入学考试成绩
    int gi;// 面试成绩
    double score;// 总成绩
    int val;// 每个学生的编号
}node[N]

vector存储每所学校的录取人数和每所学校录取学生的编号

vector<int> a(m);// 存储每所学校的录取人数
vector<vector<int>> c(m);// 存储每所学校录取学生的编号

输入完数据后,对结构体数组node进行排序:根据申请人的总分和考试分数 GE 对申请人列表node进行排序,总分越高的排在前面,当总分相等时按照 GE 来排序,GE 越高排在越前面。

排序规则:

// 注意这里必须要加引用,因为数据很大,每次排序都需要调用比较函数cmp
//不加引用会产生大量拷贝,时间效率大大降低
bool cmp(const Node& a, const Node& b)
{
   
   
    if (a.score == b.score)
    {
   
   
        return a.ge > b.ge;
    }
    return a.score > b.score;
}

排序:

sort(node, node + n, cmp);

接下来遍历申请人列表node,对每个申请人的志愿学校进行遍历。对于每个志愿学校,检查该学校的录取名额是否为0。如果申请人在符合录取规则的前提下,所有志愿学校都录满了,则表示录取失败。

如果不为0则将该申请人的编号加入该志愿学校的录取学生列表且该学校的录取名额减一,并跳出内层循环,继续遍历下一个申请人。

如果为0则获取该学校录取的最后一名学生的编号,再与他的总成绩score和考试成绩ge进行对比,如果两者都相等,也将该申请人加入该志愿学校的录取学生列表,并跳出内层循环;如果不相等则继续遍历该申请人的志愿学校列表。

那么问题来了,因为结构体数组node已经排序过了(排序前的结构体数组下标等于每个申请人的编号,排序后就不相等了),所以不能通过结构体数组下标去访问对应的申请人。

如何解决这个问题?——>在排序前,再创建一个与node一模一样的结构体数组nodecopy,不对它进行排序,这样就可以通过结构体数组下标去访问对应的申请人结构体。

可以在输入结构体数组的时候每创建了一个新的结构体,则再拷贝复制一模一样的新结构体出来。

for (int i = 0; i < n; i++)
{
   
   
    cin >> node[i].ge >> node[i].gi;
    node[i].val = i;
    node[i].score = double(node[i].ge + node[i].gi) / 2;
    int K = k;
    while (K--)
    {
   
   
        int x;
        cin >> x;
        node[i].vc.push_back(x);
    }
    nodecopy[i]=node[i];//复制一模一样的结构体数组
}

以下是分配录取结果的过程:

for (int i = 0; i < n; i++)
{
   
   
    for (int j = 0; j < node[i].vc.size(); j++)
    {
   
   
        int l = node[i].vc[j];
        if (a[l] > 0)
        {
   
   
            c[l].push_back(node[i].val);
            a[l] -= 1;
            break;
        }
        else{
   
   
            int t=c[l].back();
            if(node[i].score==nodecopy[t].score&&node[i].ge==nodecopy[t].ge)
            {
   
   
                c[l].push_back(node[i].val);
                break;
            }
        }
    }
}

最后再打印每个学校的录取结果,注意:录取结果要求升序,所以每次打印一个学校的录取结果时需要再排序

for (int i = 0; i < m; i++)
{
   
   
    if (c[i].size() > 0)
    {
   
   
        sort(c[i].begin(), c[i].end());// 需要对录取结果再进行排序
        for (int
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值