题目链接
这道题相对于之前的排序题来说,确实有点难。《算法笔记》上给的解法非常有效,但是变量有点多,很容易搞混。
书上的参考代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
struct Stu{
int GE, GI, sum;
int r,stuID;
int cho[6];
}stu[40010];
struct Sch{
int quota;
int stuNum;
int id[40010];
int lastAdmit;
}sch[110];
bool cmpStu(Stu a, Stu b){
if (a.sum!=b.sum) return a.sum>b.sum;
else return a.GE>b.GE;
}
bool cmpID(int a, int b){
return stu[a].stuID<stu[b].stuID;
}
int main(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for (int i=0; i<m; i++){
scanf("%d",&sch[i].quota);
sch[i].stuNum=0;
sch[i].lastAdmit=-1;
}
for (int i=0; i<n; i++){
stu[i].stuID=i;
scanf("%d%d",&stu[i].GE,&stu[i].GI);
stu[i].sum=stu[i].GE+stu[i].GI;
for (int j=0; j<k; j++){
scanf("%d",&stu[i].cho[j]);
}
}
sort(stu,stu+n,cmpStu);
for (int i=0; i<n; i++){
if (i>0 && stu[i].sum==stu[i-1].sum && stu[i].GE==stu[i-1].GE){
stu[i].r=stu[i-1].r;
}else {
stu[i].r=i;
}
}
for (int i=0; i<n; i++){
for (int j=0; j<k; j++){
int choice=stu[i].cho[j];
int num=sch[choice].stuNum;
int last=sch[choice].lastAdmit;
if (num<sch[choice].quota || (last!=-1 && stu[i].r==stu[last].r)){
sch[choice].id[num]=i;
sch[choice].lastAdmit=i;
sch[choice].stuNum++;
break;
}
}
}
for (int i=0; i<m; i++){
if (sch[i].stuNum>0){
sort(sch[i].id, sch[i].id+sch[i].stuNum, cmpID);
for (int j=0; j<sch[i].stuNum; j++){
printf("%d",stu[sch[i].id[j]].stuID);
if (j<sch[i].stuNum-1){
printf(" ");
}
}
}
printf("\n");
}
}
总的来看思路很明确,但是也很容易出错,变量过多导致关系有点复杂,但是关于比较函数那一段还是值得学习的。
如果少用一些全局变量,多用一些临时变量,那么变量之间的关系就会简单很多,小白也不至于看得云里雾里,我的代码:
#include <cstdio>
#include <algorithm>
using namespace std;
struct Stu{
int ge,gi,final;
int pre[10];
int rank,id;
int isAdmitted;
int admitSch;
}stu[40010];
bool cmp(Stu a, Stu b){
if (a.final!=b.final) return a.final>b.final;
else return a.ge>b.ge;
}
int main(){
int n,m,k;
scanf("%d %d %d",&n, &m, &k);
int sch[110];
for (int i=0; i<m; i++){
scanf("%d",&sch[i]);
}
for (int i=0; i<n; i++){
stu[i].id=i;
stu[i].isAdmitted=0;
scanf("%d %d",&stu[i].ge, &stu[i].gi);
stu[i].final=stu[i].ge+stu[i].gi;
for (int j=0; j<k; j++){
scanf("%d",&stu[i].pre[j]);
}
}
sort(stu,stu+n,cmp);
stu[0].rank=0;
for (int i=1; i<n; i++){
if (stu[i].final==stu[i-1].final && stu[i].ge==stu[i-1].ge){
stu[i].rank=stu[i-1].rank;
}else {
stu[i].rank=i;
}
}
int isExceeded[10]={0};
for (int i=0; i<n; i++){
stu[i].admitSch=-1;
for (int j=0; j<k; j++){
if (!stu[i].isAdmitted && !isExceeded[stu[i].pre[j]]){
stu[i].isAdmitted=1;
sch[stu[i].pre[j]]--;
stu[i].admitSch=stu[i].pre[j];
if (sch[stu[i].pre[j]]>0 || stu[i+1].rank==stu[i].rank){
isExceeded[stu[i].pre[j]]=0;
}else isExceeded[stu[i].pre[j]]=1;
break;
}
}
}
for (int i=0; i<m; i++){
int count=0;
int admit[40010];
for (int j=0; j<n; j++){
if (stu[j].admitSch==i) {
admit[count++]=stu[j].id;
}
}
sort(admit,admit+count);
for (int p=0; p<count; p++){
if (!p) printf("%d",admit[p]);
else printf(" %d",admit[p]);
}
printf("\n");
}
}
两个代码在输出部分,有很大区别, 之前的部分思路很相似,只是我的代码没有用学校这个结构体。我的代码的漏洞是,如果这几个院校不准备录取学生, 那么代码输出就是错误的, 但是实际情况下, 如果一个学校在报考名单中, 他不可能预录取的配额是0, 否则就是欺骗考生。测试点的数据也是比较正常的的数据, 是贴合实际的。