SGU 171 Sarov zones【贪心】

贪心算法

原题链接: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
time limit per test: 0.5 sec.
memory limit per test: 4096 KB
input: standard
output: standard



It is known that to participate the All-Russian Mathematic Olympiad one should do one of other olympiads enough good. These olympiads are called "zone olympiads" and the region from which people participate the same zone olympiad is called "zone". Sarov city of Nizhny Novgorod district is situated near the boundary of zones, so every year school students of Sarov participate several zones. 

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
On the first line of input there is an only integer K (1<=K<=100). On the second line there are K integers N[1], N[2], ... ,N[K] (0<=N[i]<=16000). On the third line there are K more integers Q[1], Q[2], ... ,Q[K] --- the zone levels of the zones. On the fourth line there are N integers P[1], P[2], ... P[N] --- olympiad levels of the students. (0<=Q[i]<=1000000, 0<=P[i]<=1000000). On the last (and fifth) line there are N integers w[1], w[2], ... w[k] --- the "weights" of students. 0<=w[i]<=100000. It is also guaranteed that 0<=N<=16000.

Output
Output only N integers --- Z[1], Z[2], ... Z[N] --- the numbers of zones which should be participated by students 1, 2, ... N.

Sample test(s)

Input
 
2 1 1 4 1 2 3 2 1
Output
 
2 1

题目大意:

有K个区域要在一个学校选拔学生去参加奥赛。
样例的第一行就是输入的区域个数。
每个区域有各自的限定名额,和进入的分数线,即题目中的zone level Q。给你要参赛的人的成绩和体重,让你把他们分别分到各个区域。
那么样例的第二行就有K个数,分别代表第一到第K个区域限定要选的名额。
样例的第三行也有K个数,分别对应进入相应区域的分数线Q(难度系数)。
样例第四行,各个学生的成绩。
样例第五行,对应的学生的体重。
分配好学生,并且输出各个区域参赛的学生编号。

关于输出:是按照输入时的学生顺序依次输出他们所在赛区的编号。

注意:

Keep in mind that exactly N[i] students can go to i-th zone
每一个区域都是要有N[i]个学生考试

两次都是先按照学生选了,再遍历区域...因为这里坑了很久Orz

叶:可类比于高考的录取,先划分录取,如果没有录满,则降分录取(即对于没有进入赛区的同学随机分配其实也是按照体重优先了)。


算法:贪心、sort()排序。


分析:

可以将区域按级别排序 ,从高到低依次处理。能够达到高级别区域的学生就放进去,一旦都达到了分数线,如果学生有多余,则优先考虑体重大的(学生体重从大到小排序),因为题目中奥组委要求的是希望各自的区域的选手,体重尽可能的大,所以处理当前级别时,一定优先考虑体重大的。最后剩下没有放入任何区域的学生属于不起作用的,随机放入还有名额空闲的区域即可[由于开始按照体重排序好了,所以这里还是默认了优先选的体重大的了]。 

两个排序:

1、先对区域的录取分数排序,当然是择优录取,但是因为每个学生都必须要有地方比赛、所以先对区域的分数由大到小排序。
2、再对学生排序,学生的特征有两点一个是成绩,另一个是体重。因为题目要求的是各奥组委希望自己赛区的选手的体重尽量的大,所以先考虑学生的体重,按照体重从大到小排序,再按照成绩的由小到大排序。如果体重相同(但是数据中好像没有涉及到体重相同的情况,没考虑这个,代码也A了,奇怪的题目。),则先考虑p小的,毕竟还是尽量让每个学生都达到录取线,而p大的话,选择的机会也大,所以体重相同是优先考虑p小的,当然这一点对于AC貌似没有关系。 


重做了下,发现按照分数排序出现了很多问题,各种格式错误,那么就不按照分数排序了,直接按照重量从大到小排序 ,依次遍历全部的学生,只要达到了分数线录取即可.由于开始是先排序了体重,所以后面选的时候也默认了先选体重大的,合题意.


最后如果把每个学生所在的考试区域写进了结构体,输出时还要先按照学生的编号排序下.


关于PE的坑希望路过的大神解释下:

首先题目要求是单组输入的,但是写多了,习惯性多组输入了Orz
下面我自己的这两个代码测试了下:
多组输入:


没空格,有换行 AC
有空格,有换行 AC


没空格,没换行 AC
有空格,没换行 AC


单组输入:


没空格,有换行  AC
没空格,没换行 AC


有空格,有换行 AC
有空格,没换行 AC

但是别人的也是这么写的,有的最后加个空格就过了 ,有的把下标从 0 开始改到从 1 开始就过了,开始比赛时自己也各种PE错误,PE on test 2PE on test 5 ... 还是不知道怎么会有PE


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;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值