uva1335(贪心)

来源:互联网 发布:linux系统工程师招聘 编辑:程序博客网 时间:2024/05/22 11:36

题意:
又是看了题解,感觉最近做题都没什么想法出来:
有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[N];int left[N];int right[N];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;}elsel = mid + 1;}printf("%d\n",l);}}}


0 0
原创粉丝点击