贪心算法
原题链接: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神的代码。。。
一个多月后重做。
171. Sarov zones
memory limit per test: 4096 KB
output: standard
This year K zones invited students from Sarov to participate their olympiads. i-th zone invited N[i] students, so N=N[1]+N[2]+...+N[K] totally students were invited. After the Sarov city olympiad, N students were selected, so now the olympiad authorities of Sarov have to decide, which students will participate which zone olympiad. Each student is characterized by his olympiad level and each zone is characterized by its zone level. If a student with olympiad level P participates zone with zone level Q, he will be invited to All-Russian olympiad if and only if P>Q.
Every student is also characterized by his "weight". The Sarov olympiad authorities want, that the All-Russian Olympiad will be participated by students with maximal summary weight. You are to help them. Write a program which will divide the students between zones. Keep in mind that exactly N[i] students can go to i-th zone.
Input
Output
Sample test(s)
Input
题目大意:
有K个区域要在一个学校选拔学生去参加奥赛。
样例的第一行就是输入的区域个数。
每个区域有各自的限定名额,和进入的分数线,即题目中的zone level Q。给你要参赛的人的成绩和体重,让你把他们分别分到各个区域。
那么样例的第二行就有K个数,分别代表第一到第K个区域限定要选的名额。
样例的第三行也有K个数,分别对应进入相应区域的分数线Q(难度系数)。
样例第四行,各个学生的成绩。
样例第五行,对应的学生的体重。
分配好学生,并且输出各个区域参赛的学生编号。
关于输出:是按照输入时的学生顺序依次输出他们所在赛区的编号。
注意:
叶:可类比于高考的录取,先划分录取,如果没有录满,则降分录取(即对于没有进入赛区的同学随机分配其实也是按照体重优先了)。
算法:贪心、sort()排序。
分析:
可以将区域按级别排序 ,从高到低依次处理。能够达到高级别区域的学生就放进去,一旦都达到了分数线,如果学生有多余,则优先考虑体重大的(学生体重从大到小排序),因为题目中奥组委要求的是希望各自的区域的选手,体重尽可能的大,所以处理当前级别时,一定优先考虑体重大的。最后剩下没有放入任何区域的学生属于不起作用的,随机放入还有名额空闲的区域即可[由于开始按照体重排序好了,所以这里还是默认了优先选的体重大的了]。
两个排序:
1、先对区域的录取分数排序,当然是择优录取,但是因为每个学生都必须要有地方比赛、所以先对区域的分数由大到小排序。
2、再对学生排序,学生的特征有两点一个是成绩,另一个是体重。因为题目要求的是各奥组委希望自己赛区的选手的体重尽量的大,所以先考虑学生的体重,按照体重从大到小排序,再按照成绩的由小到大排序。如果体重相同(但是数据中好像没有涉及到体重相同的情况,没考虑这个,代码也A了,奇怪的题目。),则先考虑p小的,毕竟还是尽量让每个学生都达到录取线,而p大的话,选择的机会也大,所以体重相同是优先考虑p小的,当然这一点对于AC貌似没有关系。
重做了下,发现按照分数排序出现了很多问题,各种格式错误,那么就不按照分数排序了,直接按照重量从大到小排序 ,依次遍历全部的学生,只要达到了分数线录取即可.由于开始是先排序了体重,所以后面选的时候也默认了先选体重大的,合题意.
最后如果把每个学生所在的考试区域写进了结构体,输出时还要先按照学生的编号排序下.
关于PE的坑希望路过的大神解释下:
没空格,有换行 AC
有空格,有换行 AC
没空格,没换行 AC
有空格,没换行 AC
单组输入:
没空格,有换行 AC
没空格,没换行 AC
有空格,有换行 AC
有空格,没换行 AC
2013 暑假重做代码
/*
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;
}
2012重做总结代码
//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;
}