gdoi2009中山市选T2 小球

来源:互联网 发布:岸谷新罗知乎 编辑:程序博客网 时间:2024/04/29 04:48

问题描述:

给定n个不同颜色的球,每个球都有一个分数,同时有m个瓶子,每个瓶子都有固定的容量。现在,你必须把球放到瓶子里面。请编程计算最多能放多少个球到这些瓶子里。

输入格式:

输入包含多组数据。

每组数据的第一行为两个整数n, m分别表示球的个数和瓶子的个数。

接下来的n行,每一行包含一个整数p,表示相应的球的分数。

接下来的m行,每一行包含两个整数c和q, 分别表示每个瓶子的容量(最多能装多少个球)和分数上界(放进该瓶子的每个球的分数都不能超过去q)。

当输入n,m均为0时,表示输入结束。

输出格式:

对于每组数据,输出两个整数B和S,分别表示总共能放进瓶子里的球的最大数目,以及在这个前提下,放进瓶子里面的所有球的最大分数总和。B和S以空格隔开,每组答案独占一行。

输入样例:

输出样例:

2 1

2

3

1 2

2 2

4

5

2 4

2 5

0 0

1 2

2 9

数据范围:

对于20%的数据,有1<=n<=10,0<=m<=10

对于40%的数据,有1<=n<=50,0<=m<=50。

对于全部的数据,有1<=n<=200,0<=m<=2001 <= p <= 10^6, 0 <= c <= 200, 1 <= q <= 10^6.

================================================================
这道题一开始也没思路,想写暴搜骗个20分.但是旁边的同学又在讨论,说是贪心,于是改从贪心的角度出发来思考,发现确实可行,原则就是把尽可能高分的球放在尽可能大的瓶里面,那显然要先把球的分数和瓶的分数上限排个序,然后单调队列搞一下,就可以了.感觉自己描述得不是很清楚,还是把solution放上来:
本题的标准解是贪心。因为小球本身没有体积差别,取哪个小球都只是占用相同的瓶子的体积,所以可以在所有小球中找出分值最大的那个球,看能不能找到可以放它的瓶子,如果有多个瓶子可以放这个小球,就将这个小球放在限制值最小的那个瓶子里,如果没有瓶子可以放,那么就把这个小球丢弃掉,然后用相同的方法在余下的小球中找一个最大的,放入可以放的瓶子中容量限制最小的,依次类推直到所有小球处理完。 为了方便小球的查找和瓶子的查找操作,可以先对小球按分数值进行排序,对瓶子按分数上限进行排序,然后将小球由分数从高到低进行取放尝试,对瓶子按容量限制从小到大放置,问题得解!这里排序可以采用快排,以提高算法效率。
据说此题还可以用二分图来解,不过我不会.会的人,你厉害.

#include<algorithm>
#include<fstream>
#include<functional>
using namespace std;
const int maxn = 205;
struct Tnode {
int volume, score_limit;
bool operator<(const Tnode x)const {
return score_limit > x.score_limit;
}
} bottle[maxn];
ifstream fin("ball.in");
ofstream fout("ball.out");
int n, m, score[maxn];
int main() {
while(1) {
fin >> n >> m;

if(n == 0 && m == 0)break;

for(int i = 0; i != n; ++i)fin >> score[i];

for(int i = 0; i != m; ++i)fin >> bottle[i].volume >> bottle[i].score_limit;

sort(score, score + n, greater<int>());
sort(bottle, bottle + m);
int cnt = 0, sum = 0;
int i = 0, j = 0, put_in = 0;

while(i != n && j != m) {
if(score[i] > bottle[j].score_limit) {
++i;
continue;
}

if(put_in < bottle[j].volume) {
++put_in;
++cnt;
sum += score[i++];
} else {
put_in = 0;
++j;
}
}

fout << cnt << " " << sum << endl;
}

return 0;
}

0 0