B 海盗分金币啦
Time Limit:1000MS Memory Limit:65535K
题型: 编程题 语言: 无限制
描述
现在有n个海盗,他们抢到了m个金币,现在他们准备分钱,但是由于他们聪明绝顶,
又不想直接平均分配,都想分到更多的钱,于是他们就想出了一种方法,就是让他们
按顺序排成一排,编号为1~n,现在由第一个人开始,每个人提出一种方案,如果这个
方案有除分钱的人以外一半或者一半以上的人同意,那么他们就按照这个方案分钱,否
则的话,分钱的人就要被拖去喂鲨鱼,继续由下一个人分钱,直到有人提出一个满意的方案。
现在你是第一个分钱的人,你需要保证自己存活的情况下令自己获得的钱数尽可能的多。
PS:
1.生命>金钱
2.当其他海盗能获得的金钱比分钱的海盗分给他的金钱多或者一样时,他会反对你分配的方案。
输入格式
第一行输入一个T(1<=T<=10000)
接下来T行输入n和m(1<=n<=1000,1<=m<=10000)
输出格式
输出你能得到的金钱数,当你死亡时,输出-1,每个case一行。
输入样例
2
5 100
2 100
输出样例
97
-1
Hint
当5个人分100个金币的时候
假定五个人按照分钱顺序写为1~5号
从后向前推,如果1至3号强盗都喂了鲨鱼,只剩4号和5号的话,5号一定投反对票让4号喂鲨鱼,以独
吞全部金币,四号必死。所以,4号惟有支持3号才能保命。
3号知道这一点,就会提出“100,0,0”的分配方案,对4号、5号一毛不拔而将全部金币归为已有,
因为他知道4号即使一无所获,但为了生命着想还是会投赞成票,他的方案即可通过。
不过,2号推知3号的方案,就会提出“98,0,1,1”的方案,即放弃3号,而给予4号和5号各一枚金
币。由于该方案对于4号和5号来说比在3号分配时更为有利,他们将支持他而不希望他出局而由3号来
分配。这样,2号将拿走98枚金币。
同样,2号的方案也会被1号所洞悉,1号并将提出(97,0,1,2,0)或(97,0,1,0,2)的方案,
即放弃2号,而给3号一枚金币,同时给4号(或5号)2枚金币。由于1号的这一方案对于3号和4号(或5号)
来说,相比2号分配时更优,他们将投1号的赞成票,1号的方案可获通过,97枚金币可轻松落入囊中。这
无疑是1号能够获取最大收益的方案了!
答案是:1号强盗分给3号1枚金币,分给4号或5号强盗2枚,自己独得97枚。分配方案可写成
(97,0,1,2,0)或(97,0,1,0,2)。
当只有2个人分100金币时:
推理同上:你不可能存在令最后一人满意的方案
一道模拟题,wa了我很多次,原因是因为我没想到如果某个海盗一定死了时,它会成为上一个海盗的“死党”,所以上一个海盗可以省一个金币,甚至有可能活过来。开始的时候我但但是模拟了题目的数据,一直写到13 100,果然太天真,100个金币你分很多个都分不完了,所以我就开始用金币为5来模拟,就发现了13 5 是0,14 5 是-1但是17 5是0,又奇迹地复活了,因为它有三个连续的死党了。
所以,分析完后,根据DP的思路,从后开始计数。一路向上推,打个表(不然超时),用个数组
a[i][j],表示,有i个海盗,j个金币的时候最多能拿多少钱。从而判断a[i-1][j];他的上一个能拿多少钱?如果它死了,就要找出有多少个连续的死党,我就不需要用钱贿赂它了,如果他是0,也好办,贿赂它只需要用money=need*1;其中need=i/2;就是当前人数的一半,这样能确保他>50%的,模拟下吧。如果他>0,那么,就有一个海盗要用2个金币来贿赂啦,所以money=need+1;
打个表,以后查询o(1)..233ms过了。。说多都是泪啊。
#include <stdio.h> #include <stdlib.h> #include <string.h> int a[1002][10002]; int find (int pos,int money)//找到有多少个连续的”死党“ { int i; int i_count=0; for (i=pos;i>=1;i--) { if (a[i][money]!=-1) { return i_count; } i_count++; } return i_count; } void init () { int i,j; int t; for (j=1;j<=10000;j++) { a[1][j]=j;//拿到 a[3][j]=j;//get } for (j=1;j<=10000;j++) { a[2][j]=-1;//死忙 } for (j=1;j<=10000;j++) { a[4][j]=j-2;//1---4要特殊处理,,自己看看"规律"吧 } int need; int money; for (i=5;i<=1000;i++) { for (j=1;j<=10000;j++) { need=i/2;//需要贿赂的人数 if (a[i-1][j]==0) { money=need;//就需要这么多个1 } else if (a[i-1][j]==-1)//他会死的话..可以小很多个 { t=find(i-1,j); money=need-t;//还可以少t个 } else { money=need+1;//4个海盗时是不符合这个规矩的 } if (j<money)//不够钱..死了 { a[i][j]=-1; } else { a[i][j]=j-money; } } } return ; } void work () { int n,m; scanf ("%d%d",&n,&m); printf ("%d ",a[n][m]); return ; } int main () { init (); int t; scanf ("%d",&t); while (t--) { work (); } return 0; }