经典的海盗分钱问题,原题在这里有描述:http://edward-mj.com/page/2
动态规划方案:
m个海盗
n[i][j] : 保存当由海盗i来分钱时,海盗j能得到的钱数(j>=i)
然后 在海盗i-1分钱时,当且仅当 分给海盗j( j>i )的钱数n[i-1][j] > n[i][j],才能够获得海盗j的支持。
注意,考虑一种复杂情况,当用户i 分钱怎么分都是死的时候,可以设置n[i][i] = -1. 即看作用户i只要保命就行。这种情况下,就算i-1不给i钱,i也会支持i-1. 因此n[i-1][i] =-1+1=0即可。而设置 n[i][j(j>i)]=n[i+1][j],即因为海盗i必死,所以海盗j能够获得的钱数将由i+1海盗决定
于是,对i-1海盗:
- TN(总钱数) = n[i-1][i-1] + sum( n[i-1][j] = n[i][j] +1 or 0, j=1~m, j!=i-1 ), 并要求取n[i][j]+1的次数>=(m-i+2)/2
- 如果上述方案不存在,则 n[i-1][i-1]=-1(无法保命), n[i-1][j (j>i-1) ] = n[i][j]
n[ m ] [ m ]= TN(如果只剩下一个海盗m,则他将获得所有金币)
for i=m-1 to 1:
memset( num , -1, sizeof...
num[w=0]=v=0 //w 为获得票数(不包括自己),v 为需要的金币数量
for j = i+1 to m:
for w = m-k+1 to 1:
if num[w] == -1 or num[w] > num[w-1] + n[i+1][j] :
lst[w]=j, num[w]=..... //获得j的支持,获得w票
if num[ (m - i + 2) /2 ] != -1 && num[ (m - i + 2) /2 ] <= TN: / /存在分配方案
for j = i+1 to m:
n[i][j] = n[i+1][j] + 1 or 0 //每个海盗d的金币数量
n[i][i] = TN - num[(m - i + 2) /2] //则海盗i将占有剩余钱币
else:
n[i][i] = -1 //无法分配,海盗 i 必死
for j = i+1 to m:
n[i][j] = n[i+1][j] //那么其他海盗预期获得金币数量为海盗i+1分给自己的数量
Andrew Stankevich Contest #13 Problem B 海盗分金问题
Posted on March 9, 2014
by edward_mj
Problem B Bandits
ASC是质量很高的一套题目,在codeforces的gym上开放了第1~30套。
其中多为智商题。这也就意味着,如果一题不会做,你可能想很久,查阅了很多资料,还是不会做。前几套的题解可以在shi哥的博客上找到。后面的好像就没什么题解了。当然codeforces上的红色账号可以看到标程。可是既然是智商题,本来不会做的,看了标程也往往是不明白的……
随着我们team备战ACMICPC World Finals 2014,ASC 16-30都被我们训练过了,网络上又缺乏题解,于是考虑陆陆续续写一些我们team在训练时候没有想出来的题的题解。因为学校课程/实习面试/训练/英语课等原因,我自己时间也不是特别多,于是不可能像shi哥那样一套一套地完整写了。但是我写的题对于没有达到Topcoder Codeforces双红的算法竞赛选手大概还是很有意义的。
这个海盗分金是个经典问题,但是其实不容易想对。而且条件变一下策略也要跟着变化。这题题意是这样的:
有n个海盗和m块钱(1 ≤ n, m ≤ 2000),他们要分这些钱。
分钱流程如下:先给每个强盗依次记上编号1~n。然后1号强盗提出一个钱的分配方案(也就是指定每个人获得多少钱)。剩下的人(包括1号强盗本身)对这个方案进行投票,如果支持提案的人数严格大于半数人,那么这个方案被通过,大家按数目分钱;而如果不通过,则大家把1号强盗杀掉。剩下的强盗编号都减一,人数减一,再次分钱。
假设强盗们都绝顶聪明,并且他们都认为彼此绝顶聪明。
一个强盗会反对投票,当且仅当他知道当前这个人被投死了以后,他一定会存活下来,并且获得至少和当前提案相当的金币。
现在,请你回答第一个强盗最多能提案分配给自己多少钱而不被杀。如果无论如何都会被杀,输出-1。