PAT A1080 Graduate Admission
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
word | meaning |
---|---|
automate | vt. 使自动化 |
admitted | v. 承认 |
quota | n. 配额 |
-
题意:
模拟学校录取,每个学校名额存在quota[ ]里
每个考生有两个成绩:初试GE,复试GI,及志愿表pSchool[ ]
排序规则:先按平均分(==总分),再按GE,都同并列(★并列问题)
排好序后,从第一名开始选学校,每个人都是从第一志愿开始,一直向后匹配:直到匹配到1)学校有名额2)和人并列进同一学校,或者匹配到最后一个志愿也没匹配成功 -> 没学上了
输出每个学校招的学生(递增),结尾不多空格,没有招到输出空行 -
思路 1:双指针法
将所有考生排序后,用[left , right)框住同一"排名"的人,这样从头到尾一组一组处理(以解决:并列进同一个学校的问题),若一个人有学上,就把他加入到对应学校的vector中去,最后循环将每个学校的vector排序输出 -
code 1:
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <vector>
using namespace std;
int n, m, k;
int quota[110];
vector<int> admit[110]; //存储各学校招生情况
struct Stu{
int id, gE, gI, fG, pSchool[6];
}stu[400100];
bool cmp(Stu& a, Stu& b){
//TIPS 1: 这里要使用&引用传参,不然会超时!
if(a.fG != b.fG) return a.fG > b.fG;
else return a.gE > b.gE;
}
int main(){
scanf("%d %d %d", &n, &m, &k);
for(int i = 0; i < m; ++i){
scanf("%d", "a[i]);
}
for(int i = 0; i < n; ++i){
scanf("%d %d", &stu[i].gE, &stu[i].gI);
stu[i].id = i;
stu[i].fG = stu[i].gE + stu[i].gI;
for(int j = 0; j < k; ++j){
scanf("%d", &stu[i].pSchool[j]);
}
}
sort(stu, stu+n, cmp);
int left = 0, right = 0;
while(right < n){
while(stu[right].fG == stu[left].fG && stu[right].gE == stu[left].gE && right < n){
//Wrong 1: 这个循环条件导致了最后一个测试点 段错误:
//如果right不加限制,后面都是0可能会一直累加下去,导致while执行判断条件时数组越界
right++;
}
int preS = -1; //上一个人去的学校 TIPS 2:每轮循环开始置为-1,防止边界出问题
for(int i = left; i < right; ++i){
for(int j = 0; j < k; ++j){
if(quota[stu[i].pSchool[j]] > 0){
//如果学校还有名额
quota[stu[i].pSchool[j]]--;
admit[stu[i].pSchool[j]].push_back(stu[i].id);
preS = stu[i].pSchool[j];
break<