您的位置:首页 > 其它

uva1335(贪心)

2015-01-30 15:25 246 查看
题意:

又是看了题解,感觉最近做题都没什么想法出来:

有n个人围成一个圈,其中第i个人想要ri个不同的礼物。相邻的两个人可以聊天,炫耀自己的礼物。如果两个相邻的人拥有同一种礼物,则双方都会很不高兴。问:一共需要多少种礼物才能满足所有人的需要?假设每种礼物有无穷多个,不相邻的两个人不会一起聊天,所以即使拿到相同的礼物也没关系。

比如,一共有5个人,每个人都要一个礼物,则至少要3种礼物。如果把这3种礼物编号为1, 2, 3,则5个人拿到的礼物应分别是:1,2,1,2,3。如果每个人要两个礼物,则至少要5种礼物,且5个人拿到的礼物集合应该是:{1,2},{3,4},{1,5},{2,3},{4,5}。

思路:

如果n为偶数,那么答案为相邻的两个人的r值之和的最大值,即p=max{ri+ri+1}(i=1, 2, …, n),规定rn+1=r1。不难看出,这个数值是答案的下限,而且还可以构造出只用p种礼物的方案:对于一个编号为i的人,如果i为奇数,发编号为1~r的礼物ri;如果i为偶数,发礼物p-ri+1~p,请读者自己验证它是否符合要求。

n为奇数的情况比较棘手,因为上述方法不再奏效。这个时候需要二分答案:假设已知共有p种礼物,该如何分配呢?设第1个人的礼物是1~r1,不难发现最优的分配策略一定是这样的:编号为偶数的人尽量往前取,编号为奇数的人尽量往后取。这样,编号为n的人在不冲突的前提下,尽可能地往后取了rn样东西,最后判定编号为1的人和编号为n的人是否冲突即可。比如,n = 5,A = {2, 2, 5, 2, 5},p = 8时,则第1个人取{1, 2}, 第2个人取{3, 4}, 第3个人取{8, 7, 6, 5, 2}, 第4个人取{1,
3}, 第5个人取{8, 7, 6, 5, 4},由于第1个人与第5个人不冲突,所以p = 8是可行的。

程序实现上,由于题目并不要求输出方案,因此,只需记录每个人在[1~r1]的范围内取了几个,在[r1+1~n]的范围里取了几个(在程序中分别用left[i]和right[i]表示),最后判断出第n个人在[1~r1]里面是否有取东西即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N =100005;
int n, ans, l, r;
int gift
;
int left
;
int right
;

bool judge(int total) {
int x = gift[0];
int y = total - gift[0];
left[0] = gift[0];
right[0] = 0;
for(int i = 1 ; i < n ;i++) {
if(i % 2 == 0) {
right[i] = min(y - right[i - 1] , gift[i]);
left[i] = gift[i] - right[i];
}
else {
left[i] = min(x - left[i - 1] , gift[i]);
right[i] = gift[i] - left[i];
}
}
return left[n - 1] == 0;
}
int main () {
while(scanf("%d",&n)!= EOF && n) {
for(int i = 0 ;i < n ; i++) {
scanf("%d",&gift[i]);
}
ans = 0;
for(int i = 0 ; i < n - 1;i++) {
ans = max(ans , gift[i] + gift[i + 1]);
}
ans = max(ans , gift[0] + gift[n - 1]);
if(n % 2 == 0)
printf("%d\n",ans);
else if(n == 1)
printf("%d\n",gift[0]);
else {
l = ans;
r = ans * 3;
int mid;
while(r > l) {
mid = (l + r) / 2;
if(judge(mid)) {
r = mid;
}
else
l = mid + 1;
}
printf("%d\n",l);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: