贪心算法
原题链接:http://acm.sgu.ru/problem.php?contest=0&problem=171
题目来源: http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=11221#problem/B
CSUST-2012年暑假-8月11日,组队后第5场个人训练赛
第一次中奖题目,感谢kb神的代码。。。
一个多月后重做。
有K个区域要在一个学校选拔学生去参加奥赛。
样例的第一行就是输入的区域个数。
每个区域有各自的限定名额,和进入的分数线,即题目中的zone level Q。给你要参赛的人的成绩和体重,让你把他们分别分到各个区域。
那么样例的第二行就有K个数,分别代表第一到第K个区域限定要选的名额。
样例的第三行也有K个数,分别对应进入相应区域的分数线Q(难度系数)。
样例第四行,各个学生的成绩。
样例第五行,对应的学生的体重。
分配好学生,并且输出各个区域参赛的学生编号。
叶:可类比于高考的录取,先划分录取,如果没有录满,则降分录取(即对于没有进入赛区的同学随机分配其实也是按照体重优先了)。
可以将区域按级别排序 ,从高到低依次处理。能够达到高级别区域的学生就放进去,一旦都达到了分数线,如果学生有多余,则优先考虑体重大的(学生体重从大到小排序),因为题目中奥组委要求的是希望各自的区域的选手,体重尽可能的大,所以处理当前级别时,一定优先考虑体重大的。最后剩下没有放入任何区域的学生属于不起作用的,随机放入还有名额空闲的区域即可[由于开始按照体重排序好了,所以这里还是默认了优先选的体重大的了]。
1、先对区域的录取分数排序,当然是择优录取,但是因为每个学生都必须要有地方比赛、所以先对区域的分数由大到小排序。
2、再对学生排序,学生的特征有两点一个是成绩,另一个是体重。因为题目要求的是各奥组委希望自己赛区的选手的体重尽量的大,所以先考虑学生的体重,按照体重从大到小排序,再按照成绩的由小到大排序。如果体重相同(但是数据中好像没有涉及到体重相同的情况,没考虑这个,代码也A了,奇怪的题目。),则先考虑p小的,毕竟还是尽量让每个学生都达到录取线,而p大的话,选择的机会也大,所以体重相同是优先考虑p小的,当然这一点对于AC貌似没有关系。
重做了下,发现按照分数排序出现了很多问题,各种格式错误,那么就不按照分数排序了,直接按照重量从大到小排序 ,依次遍历全部的学生,只要达到了分数线录取即可.由于开始是先排序了体重,所以后面选的时候也默认了先选体重大的,合题意.
最后如果把每个学生所在的考试区域写进了结构体,输出时还要先按照学生的编号排序下.
/* Accepted 1075 KB 46 ms Visual Studio C++ 2010 2050 B */ #include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; const int maxQ = 110; const int maxP = 16000+10; struct Qone{ int index; int level; int studentNum; }Q[maxQ]; struct People{ int index; int level; int weight; int qone; }P[maxP]; bool cmp1(Qone A, Qone B) { return A.level > B.level; } bool cmp2(People A, People B) { return A.weight > B.weight; } bool cmp3(People A, People B) { return A.index < B.index; } int main() { int K, N; while(scanf("%d", &K) != EOF) { N = 0; for(int i = 1; i <= K; i++) { scanf("%d",&Q[i].studentNum); Q[i].index = i; N += Q[i].studentNum; } for(int i = 1; i <= K; i++) { scanf("%d", &Q[i].level); } sort(Q+1,Q+K+1,cmp1); //Level Max to min for(int i = 1; i <= N; i++) { scanf("%d", &P[i].level); P[i].index = i; P[i].qone = 0; } for(int i = 1; i <= N; i++) { scanf("%d", &P[i].weight); } sort(P+1, P+N+1, cmp2); //Weight Max to min for(int i = 1; i <= N; i++) //先按照达到 level 的选 { for(int j = 1; j <= K; j++) { if(Q[j].studentNum > 0) { if(P[i].level > Q[j].level) { P[i].qone = Q[j].index; Q[j].studentNum--; break; } } } } int j = 1; for(int i = 1; i <= N; i++) // 按照体重由大到小随意分配剩下的学生,保证每个学生都有考试区域 { if(P[i].qone != 0) continue; while(Q[j].studentNum == 0) j++; P[i].qone = Q[j].index; Q[j].studentNum--; } sort(P+1, P+1+N, cmp3); for(int i = 1; i <= N; i++) { if(i == 1) printf("%d", P[i].qone); else printf(" %d", P[i].qone); } printf("\n"); } return 0; }
//Accepted 1139 KB 46 ms Visual Studio 8 C++ 1338 B 2012-09-22 15:44:41 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXK=100+10; const int MAXN=16000+10; struct Zone { int index;//编号 int N;//需要的人数 int Q;//进入该区域的分数线 }zone[MAXK]; struct Stu { int index;//编号 int P;//水平 int w;//重量 }stu[MAXN]; int p[MAXN]; bool cmp1(Zone a,Zone b)//按照Q从大到小排序 { return a.Q>b.Q; } bool cmp2(Stu a,Stu b)//按照w从大到小排序 { return a.w>b.w; } int main() { int k; int i,j; int num=0; scanf("%d",&k); for(i=0;i<k;i++) { zone[i].index=i+1; scanf("%d",&zone[i].N); num+=zone[i].N; } for(i=0;i<k;i++) scanf("%d",&zone[i].Q); sort(zone,zone+k,cmp1); for(i=0;i<num;i++) { stu[i].index=i+1; scanf("%d",&stu[i].P); } for(i=0;i<num;i++) scanf("%d",&stu[i].w); sort(stu,stu+num,cmp2); memset(p,-1,sizeof(p)); for(i=0;i<num;i++)//第一轮先分配成绩达到了的 { for(j=0;j<k;j++) { if(stu[i].P>zone[j].Q && zone[j].N)//注意:是stu[i].P>zone[j].Q不是>= { p[stu[i].index]=zone[j].index; zone[j].N--; break;//依次对排好序的学生逐个从排好序的区域逐个安排 }//也就是说对下一个学生也从第一个区域开始排 } } j=0; for(i=0;i<num;i++)//分配剩下的人 { if(p[i+1]!=-1) continue;//表示已经分配 while(zone[j].N==0) j++;//表示当前区域已经招满 p[i+1]=zone[j].index; zone[j].N--; } for(i=1;i<=num;i++) printf("%d ",p[i]); return 0; }