目录
1,题目描述
- proceed:继续做(或从事、进行); 接着做; 继而做; 行进;
- quota:定量,指标;
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
题目大意
模拟考生报志愿录取的情形。每名考生可报一定数目的志愿,学校则根据报名的学生,按照排名次序,若名额未满则录取,若已录取满,但下一名考生的totlaG和GE均与该校录取的最后一名考生相等,则仍会录取。
注意,排名优先:按照排名的先后顺序,确定一个考生的录取状态(录取/未录取)后,再处理下一名考生。
2,思路
数据结构
- int quota[101]:每个学校招生人数;
- struct node{
int id, GE, totalG;
int sel[6];//选择的志愿
}; 存放每名考生的信息; - vector<int> school[101]:存放每个学校录取的考生id;
- vector<node> student:存放所有考生的信息;
- node lastStu[101]:存放每个学校 录取的最后一名学生
算法
- 将所有考生的数据读入student中,并根据设计的排序函数cmp1,对学生排序:
- 按照对学生排序后的顺序,依次处理每位考生的志愿(志愿未满 / 志愿已满,但成绩与最后一位录取的考生相同 / 其他),确认录取状态后,再处理下一位考生:
- 将每个学校录取的考生,按照学号升序排序并输出:
3,AC代码
#include<bits/stdc++.h>
using namespace std;
int N, M, K; //N报名人数 M学校数目 K志愿数目
int quota[101]; //每个学校招生人数
struct node{
int id, GE, totalG;
int sel[6]; //选择的志愿
};
vector<int> school[101]; //每个学校一个vector 存放录取学生的id
vector<node> student;
bool cmp1(node a, node b){
if(a.totalG != b.totalG)
return a.totalG > b.totalG;
else{
if(a.GE != b.GE)
return a.GE > b.GE;
else
return a.id < b.id;//没有此规定 但为了保证逻辑严密
}
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d %d %d", &N, &M, &K);
for(int i = 0; i < M; i++)
scanf("%d", "a[i]);
int GE, GI;
int sel[6];
node n;
for(int i = 0; i < N; i++){
scanf("%d %d", &GE, &GI);
n.id = i;
n.GE = GE;
n.totalG = GE + GI;
for(int j = 0; j < K; j++) scanf("%d", &n.sel[j]);
student.push_back(n);
}
sort(student.begin(), student.end(), cmp1);
node lastStu[101]; //存放每个学校 录取的最后一名学生
for(int i = 0; i < student.size(); i++){
for(int j = 0; j < K; j++){
int sch = student[i].sel[j];
if(school[sch].size() < quota[sch]){
school[sch].push_back(student[i].id);
lastStu[sch] = student[i]; //更新最后一名录取的学生
break; //录取成功
}else if(student[i].totalG == lastStu[sch].totalG &&
student[i].GE == lastStu[sch].GE){ //名额已满 但排名相同
school[sch].push_back(student[i].id);
break; //录取成功
}
}
}
for(int i = 0; i < M; i++){
sort(school[i].begin(), school[i].end());
if(school[i].size() != 0){
printf("%d", school[i][0]);
for(int j = 1; j < school[i].size(); j++)
printf(" %d", school[i][j]);
}
printf("\n");
}
return 0;
}
4,解题过程
第一搏
有一个疑问,就是如果第几轮选拔后,学校的名额已满,但是下一轮选拔中的第一名与上一轮的最后一名成绩相同(区别是选志愿的顺序)怎么办?
于是我先按照志愿优先的方法(依次考虑所有人的志愿,以第一志愿为例,假设一名考生,就算排名靠前,如果他第一志愿的学校已经录取满,则只能等待第二志愿了。而就算最后一名,他的第一志愿学校未录取满,他仍可以被录取)
#include<bits/stdc++.h>
using namespace std;
int N, M, K;//N报名人数 M学校数目 K志愿数目
int quota[101];//每个学校招生人数
struct node{
int id, GE, totalG;
int sel[6];//选择的志愿
bool admit;
};
vector<int> school[101];//每个学校一个vector 存放录取学生的id
vector<node> student;
bool cmp1(node a, node b){
if(a.totalG != b.totalG)
return a.totalG > b.totalG;
else{
if(a.GE != b.GE)
return a.GE > b.GE;
else
return a.id < b.id;//没有此规定 但为了保证逻辑严密
}
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
scanf("%d %d %d", &N, &M, &K);
for(int i = 0; i < M; i++)
scanf("%d", "a[i]);
int GE, GI;
int sel[6];
node n;
for(int i = 0; i < N; i++){
scanf("%d %d", &GE, &GI);
n.id = i;
n.GE = GE;
n.totalG = GE + GI;
n.admit = false;
for(int j = 0; j < K; j++) scanf("%d", &n.sel[j]);
student.push_back(n);
}
sort(student.begin(), student.end(), cmp1);
bool full[101];//学校在一轮的录取中是否已经录取满
node lastStu[101];//存放每个学校 每轮录取的最后一名学生
for(int i = 0; i < K; i++){//K轮选课
vector<int> fullSch;//本轮录取满的学校
for(int j = 0; j < student.size(); j++){
if(student[j].admit == false){
int sch = student[j].sel[i];
if(!full[sch]){//该学校上一轮未选满
if(school[sch].size() < quota[sch]){//该学校本轮中还有名额
school[sch].push_back(student[j].id);
student[j].admit = true;
lastStu[sch] = student[j];
}
else if(student[j].totalG == lastStu[sch].totalG &&
student[j].GE == lastStu[sch].GE){//名额已满 但排名相同
fullSch.push_back(sch);
school[sch].push_back(student[j].id);
student[j].admit = true;
}
}
}
}
for(auto a : fullSch){//将本轮已录取满的学校做标记
full[a] = true;
}
fullSch.clear();//每轮结束后清空
}
for(int i = 0; i < M; i++){
sort(school[i].begin(), school[i].end());
if(school[i].size() != 0){
printf("%d", school[i][0]);
for(int j = 1; j < school[i].size(); j++)
printf(" %d", school[i][j]);
}
printf("\n");
}
return 0;
}
没办法,,,手动演算了一遍,按照原先设想的算法规则,确实应该是这样。
看来是规则没理解清楚。。。
第二搏
根据演算过程,重新设计了规则:
排名优先,按照排名依次考虑每个学生,若第一志愿已满,则依次考虑其他志愿,直到被录取或所有志愿均已满未被录取,则考虑下一位考生。
那就很简单了嘛<( ̄ c ̄)y▂ξ
逻辑更加直白了。
一道大题做出了两道大题的感觉,我很快乐/(ㄒoㄒ)/~~