海盗分金--大于半数才成立

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;
}
原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5137999.html