PTA甲级1080 Graduate Admission (30point(s))

首先,先贴柳神的博客

https://www.liuchuo.net/ 这是地址

想要刷好PTA,强烈推荐柳神的博客,和算法笔记

题目原文

It is said that in 2011, there are about 100 graduate schools ready to proceed over 40,000 applications in Zhejiang Province. It would help a lot if you could write a program to automate the admission procedure.

Each applicant will have to provide two grades: the national entrance exam grade GE, and the interview grade GI. The final grade of an applicant is (GE+GI)/2. The admission rules are:

  • The applicants are ranked according to their final grades, and will be admitted one by one from the top of the rank list.
  • If there is a tied final grade, the applicants will be ranked according to their national entrance exam grade *G**E*. If still tied, their ranks must be the same.
  • Each applicant may have K choices and the admission will be done according to his/her choices: if according to the rank list, it is one's turn to be admitted; and if the quota of one's most preferred shcool is not exceeded, then one will be admitted to this school, or one's other choices will be considered one by one in order. If one gets rejected by all of preferred schools, then this unfortunate applicant will be rejected.
  • If there is a tied rank, and if the corresponding applicants are applying to the same school, then that school must admit all the applicants with the same rank, even if its quota will be exceeded.

Input Specification:

Each input file contains one test case.

Each case starts with a line containing three positive integers: N (≤40,000), the total number of applicants; M (≤100), the total number of graduate schools; and K (≤5), the number of choices an applicant may have.

In the next line, separated by a space, there are M positive integers. The i-th integer is the quota of the i-th graduate school respectively.

Then N lines follow, each contains 2+K integers separated by a space. The first 2 integers are the applicant's *G**E* and *G**I, respectively. The next K* integers represent the preferred schools. For the sake of simplicity, we assume that the schools are numbered from 0 to M−1, and the applicants are numbered from 0 to N−1.

Output Specification:

For each test case you should output the admission results for all the graduate schools. The results of each school must occupy a line, which contains the applicants' numbers that school admits. The numbers must be in increasing order and be separated by a space. There must be no extra space at the end of each line. If no applicant is admitted by a school, you must output an empty line correspondingly.

Sample Input:

11 6 3
2 1 2 2 2 3
100 100 0 1 2
60 60 2 3 5
100 90 0 3 4
90 100 1 2 0
90 90 5 1 3
80 90 1 0 2
80 80 0 1 2
80 80 0 1 2
80 70 1 3 2
70 80 1 2 3
100 100 0 2 4  

Sample Output:

0 10
3
5 6 7
2 8
1 4

生词如下

Graduate 研究生

Admission 录用

entrance exam grade 入学考试成绩

interview grade 面试成绩

题目大意

给你N个学生,然后给考试成绩和面试成绩,在给M个学校

这M个学校他们收的人都不同,每个学生最多可以报K个学校

题目要求如下

① M个学校收入是按照成绩好坏来排的,先是按照考试成绩和面试成绩的平均分,如果考试成绩和面试成绩相同的话,在优先录取按照考试成绩高的

② 如果有人的平均分和考试成绩都一样的话,学校可以破格都录取

③ 最后一行是一定要多输出的,PTA的格式问题,都搞不清楚的我.

我的代码如下

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct student {
    int grade[3];
    vector<int>choice;
    int rank;
    int id;
};
struct School {
    vector<int> people;
    int last;   //记录上一次的分数
    int Max;
};
bool cmp(student a, student b) {
    if (a.grade[2] != b.grade[2])   return a.grade[2] > b.grade[2];
    else
        return a.grade[0] > b.grade[0];
}
int main(void) {
    int N, M, K;
    scanf("%d%d%d", &N, &M, &K);
    vector<School> Sch(M);
    vector<student> data(N);
    for (int i = 0; i < M; i++) scanf("%d", &Sch[i].Max);
    for (int i = 0; i < N; i++) {
        int t;
        scanf("%d%d", &data[i].grade[0], &data[i].grade[1]);
        data[i].grade[2] = data[i].grade[0] + data[i].grade[1];
        for (int j = 0; j < K; j++) {
            scanf("%d", &t);
            data[i].choice.push_back(t);
        }
    }
    for (int i = 0; i < N; i++)     data[i].id = i;
    sort(data.begin(), data.end(), cmp);
    data[0].rank = 1;
    for (int i = 1; i < N; i++) {
        if (data[i].grade[2] == data[i - 1].grade[2] && data[i].grade[0] == data[i - 1].grade[0]) {
            data[i].rank = data[i - 1].rank;
        }
        else
            data[i].rank = i + 1;
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < K; j++) {
            if (Sch[data[i].choice[j]].Max > 0) {
                Sch[data[i].choice[j]].Max--;
                Sch[data[i].choice[j]].people.push_back(data[i].id);    //把这个人放进去
                Sch[data[i].choice[j]].last = data[i].rank;
                break;
            }
            else {
                if (data[i].rank <= Sch[data[i].choice[j]].last) {
                    Sch[data[i].choice[j]].people.push_back(data[i].id);    //把这个人放进去
                    Sch[data[i].choice[j]].last = data[i].rank;
                    break;
                }
            }
        }
    }
    for (int i = 0; i < M; i++) {
        sort(Sch[i].people.begin(), Sch[i].people.end());
        for (auto it = Sch[i].people.begin(); it != Sch[i].people.end(); it++) {
            if (it != Sch[i].people.begin()) {
                printf(" ");
            }
            printf("%d", *it);
        }
        printf("\n");
    }
    return 0;
}

柳神的思路

分析:
1.stu容器里放学生{id, ge, gi, fin, choice(容器里放学生报考学校的id)}, quota数组放招生计划的数量,cnt数组存放当前学校已经招收的学生数,sch数组里放的容器,容器里是学校已经招的学生的id~
2.对学生按照分数排序,依次学生遍历,分数最高的学生先挑学校~
3.对于每个学生录取到哪里:依次遍历学生的报考志愿,如果(没招满 || 他与已经招的学生的最后一名成绩并列)就把他招进去,该学生录取结果即可确定,更新该学校已经招生的人数,并把次学生加入该学校录取容器中~
4.输出学校录取情况时学生id顺序是乱的,要先从小到大排序,然后输出。每个学校占一行~
5.排序函数要用 & 引用传参,不然会超时~
6.因为分数 fin = ge + gi 不会超出int, fin / 2 和fin排名效果一样, 不除2不会影响结果,而且还可以巧妙躲避除2后double不能精确表示的问题~

柳神的代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct peo {
    int id, ge, gi, fin;
    vector<int> choice;
};
bool cmp(peo& a, peo& b) {
    if (a.fin != b.fin) return a.fin > b.fin;
    return a.ge > b.ge;
}
bool cmp2(peo& a, peo& b) {
    return a.id < b.id;
}
int main() {
    //quota,就是学校的人数
    int n, m, k, quota[110], cnt[110] = { 0 };
    scanf("%d%d%d", &n, &m, &k);
    vector<peo> stu(n), sch[110];
    for (int i = 0; i < m; i++)
        scanf("%d", &quota[i]);
    for (int i = 0; i < n; i++) {
        scanf("%d%d", &stu[i].ge, &stu[i].gi);  
        stu[i].id = i;  //这一步我还用了一个循环
        stu[i].fin = stu[i].ge + stu[i].gi;
        stu[i].choice.resize(k);    //分配了一个这么大的空间
        for (int j = 0; j < k; j++)
            scanf("%d", &stu[i].choice[j]);
    }
    sort(stu.begin(), stu.end(), cmp);

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < k; j++) {
            int schid = stu[i].choice[j];
            int lastindex = cnt[schid] - 1;
            if (cnt[schid] < quota[schid] || (stu[i].fin == sch[schid][lastindex].fin) && stu[i].ge == sch[schid][lastindex].ge) {
                sch[schid].push_back(stu[i]);
                cnt[schid]++;
                break;
            }
        }
    }
    for (int i = 0; i < m; i++) {
        sort(sch[i].begin(), sch[i].end(), cmp2);
        for (int j = 0; j < cnt[i]; j++) {
            if (j != 0) printf(" ");
            printf("%d", sch[i][j].id);
        }
        printf("\n");
    }
    return 0;
}

总结和反思

① 柳神用了cnt来保存学校招的人,这样就可以不用多判断

② 柳神没有搞那个rank,而我搞了,后来想想也是可以不用的

猜你喜欢

转载自www.cnblogs.com/a-small-Trainee/p/12457955.html