bnu24252 海盗分赃

题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=24252

这是四川2012年省赛的一道题,背景:海盗分宝藏。大概题意:给你N种价值的物品,物品有两个属性,一个是数量,一个是价值(价值是以2的ai次方表示的)。为了公平起见,求出宝藏分配的最小差(二进制表示)。

思路:当我们把宝藏合成后,即2*2^(n-1)宝藏=1*2^n宝藏(即二进制的进位处理),如果价值最大的宝藏可一分为二,那么该宝藏不会影响最终的结果(即该部分差值为0),如果价值最大的宝藏不可平分,那么必定结果必定是 该宝藏的价值-剩余宝藏的和 。(当进位处理后,差值最小的情况:2^n-(2^(n-2)+2^(n-2)+…+2^2+2^1)=1)。维护一个模拟二进制数组来记录宝藏的分布,比如a[2]=4表示2的2次方的宝藏有4个;然后进行进位处理,这时候我们需要一个标记数组,为什呢?因为当进位后如果某一位是1,这个1有两种情况:1>、这个1是进位得到的,那么它可以转换为比它低一位的2,比如:a[2]=1(进位的到),a[1]=0;这个时候相当于a[1]=2,即宝藏是可分的,不会影响结果。2>、这个1是本身就有的,那么则意味着该宝藏不可分,也就是找到可以得到答案的最大宝藏。很显然我们需要标记进位过程中哪一位的1是由进位得到的(这个过程很重要)。那么剩下的问题就是二进制的相减:题目中的减法很有特点,一定是1000000…(n个0)减去另一个二进制数,我们可以把这个二进制数转换为111111111…(n个1)+1;下面相减的过程就是一个简单的取反过程。代码如下

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <cstdlib>
 5 #include <ctime>
 6 #include <iostream>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <queue>
10 #include <map>
11 #include <set>
12 #include <string>
13 #define OUT(x) cout << #x << ": " << (x) << endl
14 using namespace std;
15 typedef long long LL;  //注意要用long long存
16 const int maxn=100005;
17 const int INFF=999999999;
18 LL a[maxn];
19 LL ans[maxn];
20 bool fg[maxn];
21
22 int main()
23 {
24     int T,i,cas=1;
25     scanf("%d",&T);
26     while(T--)
27     {
28         memset(a,0,sizeof a);
29         memset(fg,false,sizeof fg);
30         memset(ans,0,sizeof ans);
31
32         int n,val,num,max=0;
33         scanf("%d",&n);
34         for(i=0;i<n;i++)
35         {
36             scanf("%d %d",&val,&num);
37             if(max<val)    //记录最大价值id
38                 max=val;
39             a[val]+=num;
40         }
41         for(i=0;i<=max;i++)
42         {
43             if(a[i]>=2)
44             {
45                 a[i+1]+=a[i]/2;  //注意好顺序
46                 a[i]%=2;
47                 fg[i+1]=true;
48             }
49         }
50
51         int id=0;
52         for(i=max;i>0;i--)
53         {
54             if(a[i]%2 == 1&& !fg[i])
55             {
56                 id=i;
57                 break;
58             }
59         }
60         printf("Case #%d: ",cas++);
61         if(id == 0)       //判断
62         {
63             printf("%lld\n",a[0]);
64             continue;
65         }
66
67         ans[0]=1;
68         for(i=id-1;i>=0;i--)
69             ans[i]+=(1-a[i]%2);
70         for(i=0;i<=id;i++)
71             if(ans[i]>=2)
72             {
73                 ans[i]=0;
74                 ans[i+1]++;
75             }
76         for(i=id+1;i>=0;i--)
77         {
78             if(ans[i] == 1)
79                 break;
80         }                    //去除前导0
81         for(;i>=0;i--)
82             printf("%lld",ans[i]);
83         puts("");
84     }
85     return 0;
86 } 
时间: 2024-10-21 21:49:13

bnu24252 海盗分赃的相关文章

(算法)海盗分赃_2

分享一篇趣文(来自伯乐在线:http://blog.jobbole.com/70395/),同样是海盗分赃问题,这篇文章以诙谐幽默的口吻以及浅显易懂的对话来解释海盗分赃问题. 与上一篇博文海盗分赃_1不同的是,这里的投票规则为半数即可,并不要求大于半数.因此该问题的思路过程结果为: (300,0) (299,0,1) (299,0,1,0) (298,0,1,0,1) (298,0,1,0,1,0) 文章如下: #算法题# 6个海盗要分赃300金币.规则是由资格最老的海盗提出各人分到的数量,然后

【博弈】海盗分赃

题目大意:有N(N<=1000)个贪婪的海盗,他们得到了100,000个金币,决定分赃.他们都很精明,都想自己利益最大化,并采取如下策略: 1. 首先N人排好次序. 2. 由编号最大者给出分赃方案. 3. 所有人表决,50%及以上的人赞成就分赃成功,否则转4. 4. 杀掉提案者(总人数少了1),转2. 你的任务:判断第几号海盗得最多金币,有多少个. 题解:此题需要绕一个小弯,首先,获得钱最多的一定是第一个人.其次,他只需给所有奇数号的人一枚金币.可以YY一下,奇数永远都受偶数的限制,他们非常可能

2-10. 海盗分赃(25) (ZJUPAT 数学)

题目链接:http://pat.zju.edu.cn/contests/ds/2-10 P个海盗偷了D颗钻石后来到公海分赃,一致同意如下分赃策略: 首先,P个海盗通过抽签决定1-P的序号.然后由第1号海盗提出一个分配方案(方案应给出每个海盗分得的具体数量),如果能够得到包括1号在内的绝对多数(即大于半数)同意,则按照该分配方案执行,否则1号将被投入大海喂鲨鱼:而后依次类似地由第2号.第3号等等海盗提出方案,直到能够获得绝对多数同意的方案出现为止,或者只剩下最后一位海盗,其独占所有钻石.请编写一个

(算法)海盗分赃_1

题目: P个海盗偷了D颗钻石后来到公海分赃,一致同意如下分赃策略: 首先,P个海盗通过抽签决定1-P的序号.然后由第1号海盗提出一个分配方案(方案应给出每个海盗分得的具体数量),如果能够得到包括1号在内的绝对多数(即大于半数)同意,则按照该分配方案执行,否则1号将被投入大海喂鲨鱼:而后依次类似地由第2号.第3号等等海盗提出方案,直到能够获得绝对多数同意的方案出现为止,或者只剩下最后一位海盗,其独占所有钻石.请编写一个程序,给出第1号海盗的钻石分配方案中自己分得的钻石数量. 附带的三个假定: 1)

进阶实验2-3.1 海盗分赃 (25分)

P 个海盗偷了 D 颗钻石后来到公海分赃,一致同意如下分赃策略: 首先,P 个海盗通过抽签决定 1 - P 的序号.然后由第 1 号海盗提出一个分配方案(方案应给出每个海盗分得的具体数量),如果能够得到包括 1 号在内的绝对多数(即大于半数)同意,则按照该分配方案执行,否则 1 号将被投入大海喂鲨鱼:而后依次类似地由第 2 号.第 3 号等等海盗提出方案,直到能够获得绝对多数同意的方案出现为止,或者只剩下最后一位海盗,其独占所有钻石.请编写一个程序,给出第 1 号海盗的钻石分配方案中自己分得的钻

【小米oj】 海盗分赃

背包 #define mm(a) memset(a,0,sizeof(a)); #define max(x,y) (x)>(y)?(x):(y) #define min(x,y) (x)<(y)?(x):(y) #define Fopen freopen("1.in","r",stdin); freopen("m.out","w",stdout); #define rep(i,a,b) for(int i=(a);

算法浅谈——递归算法与海盗分金问题

本文始发于个人公众号:TechFlow 最近看到一道很有意思的问题,分享给大家. 还是老规矩,在我们聊算法问题之前,先来看一个故事. 传说中,有5个海盗组成了一支无敌的海盗舰队,他们在最后一次的寻宝当中找寻到了100枚价值连城的金币.于是,很自然的,这群海盗面临分赃的问题.为了防止海盗内讧,残忍的海盗们制定了一个奇怪的规则: 他们决定按照功劳大小对五个人进行编号,由编号小的海盗先提出分配方案.如果方案能够得到大多数人的同意,那么就按照他提出的方案进行分配.如果不能通过,说明他已经失去了威望,海盗

海盗分金问题(博弈)

NBUOJ 2680:海盗分金 题意: 有N个海盗要分M金币,将N个海盗从1-N编号,由第一个人提出分配方案,一人一票(分配者也拥有一票),超过半数同意方案才被通过,否则他将被扔入大海喂鲨鱼,接下来由下一人分配,以此类推. 分析:从3个人的状态往后推,每次处理出当前分配方案下的被分到0,1 金币的海盗数量,当前被分到0,下次并然分到1,当前分到1的判断是否需要分配2才能满足通过条件,最后输出分配剩余的金币数即可. 代码: 1 #include "cstdio" 2 #include &

好玩的智力小游戏(海盗分金)

 海盗的难题(Ian Stewart) 数学的逻辑有时会导致看来十分怪异的结论. 一般的规则是.假设逻辑 推理没有漏洞. 那么结论就必然站得住脚,即使它与你的直觉矛盾. 1998 年9月,加利福尼亚州帕洛阿 尔托的Stephen M. Omohundro寄给我一道难题, 它恰好就属于这一类.这难题已经流传 了至少十年,可是Omohundro对它作 了修改,使它的逻辑问题变得分外复杂了. 先来看看此难题原先的形状. 10名海盗抢得了窖藏的100块金子,并打算 瓜分这些战利 品.这是一些讲民主的