zoukankan      html  css  js  c++  java
  • hdu 1538 A Puzzle for Pirates 博弈论

    很经典的问题,思路转载自 http://blog.csdn.net/ACM_cxlove?viewmode=contents

    题目:这是一个经典问题,有n个海盗,分m块金子,其中他们会按一定的顺序提出自己的分配方案,如果50%以上的人赞成,则方案通过,开始分金子,如果不通过,则把提出方案的扔到海里,下一个人继续。

    首先我们讲一下海盗分金决策的三个标准:保命,拿更多的金子,杀人,优先级是递减的。

     

    同时分为两个状态稳定状态和不稳定状态:如果当n和m的组合使得最先决策的人(编号为n)不会被丢下海, 即游戏会立即结束, 就称这个状态时"稳定的". 反之, 问题会退化为n-1和m的组合, 直到达到一个稳定状态, 所以乘这种状态为"不稳定的".

    接下来我们从简单的开始分析:
    如果只有两个人的话:那么2号开始提出方案,这时候知道不管提什么,他自己肯定赞成,过半数,方案通过,那么2号肯定把所有的金子都给了自己。
    如果只有三个人的话:那么3号知道,如果自己死了,那么2号肯定能把所有金子拿下,对于1号来说没有半点好处。
    那么他就拿出金子贿赂1号,1号拿到1个金子,总比没有好,肯定赞成3号,剩下的3号拿下。
    如果只有四个人的话:那么4号知道,如果自己死了,那么1号拿到1个金子,2号什么都没有,3号拿下剩下的金子。
    那他就可以拿出部分金子贿赂2号,2号知道如果4号死了,自己将什么都没有,他肯定赞成4号。
    如此类推下去,貌似就是第一个决策的时候,与他奇偶性相同的人会被贿赂拿到1个金子,剩下的全归提出方案的人所有。
     
    但是会有一个问题便是,如果金子不够贿赂怎么办。
    情况1、我们首先归纳之前的,如果n<=2*m时候,前面与n相同奇偶性的得到1个金子,剩下的第n个人拿下。
    情况2、如果n==2*m+1,第n个人拿出m个金子贿赂前面的m个人。自己不拿金子,这样刚好保证自己不死,这就是之前提到的优先级,首先得保命,如果自己拿了一个金子,那么前面就有一个人会反对,因为对于那个人,不管怎么样都分不到金子,则轮到第三个原则,杀人,肯定投反对票。
     
    剩下来我们考虑,钱不够贿赂的情况:
    我们将问题具体化:如果有500个海盗,只有100个金子,那么前面201个已经分析过了。
    对于202号来说,自己不能拿金币,而贿赂上一轮没有拿到金币的101人中的100人就够了。
    对于203号来说,需要102个人的支持,显然加上他自己,还需要101票,而金子不够贿赂,别人会反对,而达到杀人的目的。
    对于204号来说,他知道一旦自己死了,203号是必死,抓住这点,203必然支持他,因为203号宁可不要金币,也要保住性命,所以204号把100个金币分给之前的100个人,然后203和他自己的两票保证自己不死。
    对于205号来说,203,和204是不会支持他的,因为一旦205死了,他们不仅可以保住性命,而且还可以看着205死掉。所以205是必死
    那么206呢,虽然205必死,会支持他,但是还是缺一票,所以必死。
    对于207呢,205和206之前是必死,会支持他,但是加上自己以及100个贿赂名额,还是必死
    对于208号,205,206.,207因为后面是必死的,肯定会支持208成功,那么208刚好能凑齐104票,得以保命。
     
    以下我们猜想:n=2*m+2^k的情况下,是可以保命的,称为稳定状态,否则为不稳定状态,我们证明一下:
    首先对于n来说,有m票贿赂,但是对于2*m+2^(k-1)以前必死的死,他们会支持2*m+2^(k-1),因为他们肯定拿不到钱,而且支持2*m+2^(k-1),另外根据杀人原则,希望之后的人都死,轮到2*m+2^(k-1)决策的时候保命就行了。
    同理2*m+2^(k-1)到2*m+2^k之间的2^(k-1)-1个人来说,他们必死,所以必定支持2*m+2^k,加上m个金币贿赂的,加上他自己,刚好有m+2^(k-1)。这样刚好凑齐一半,可以不死。
    证明完毕:2*m+2^k的人可以保命,否则必死。
     
    我们考虑一下分金币情况:
    情况3:对于第2*m+2^k个人来说,他可以保命,肯定分不到金子,而他手上的m个金子,可以贿赂m个人,但是具体是哪些人是不定的。则不管是不能分到金子,还是可能分不到金子的人来说,结果都为0。
    情况4:对于2*m+2^(k-1)到2*m+2^k之间的来说,他们的决策是必死,而在他们决策的时候,其它人分得金币情况也为0。
     
    我们来解释一下金币的不确定性:

    金币数量的不确定性:由上面的推理可知, 当n=2m+2时, 上一轮推理没有分到金币的人的金币数量首次具有不确定性, 并且在n>2m+2时, 这种不确定性一定会延续下去, 轮到因为n号决策者之前的一个人决策时, 那个人肯定分不到金币了, 所以在上一轮推理中没有分到金币的人的个数一定大于m.

    综合情况1,2,3,4便是本题的解,
    代码如下:
     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define I(x) scanf("%d",&x)
     6 #define ll __int64
     7 #define MAX 500000
     8 using namespace std;
     9 int f[15]={2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
    10 void solve(int n,int m,int p)
    11 {
    12     if(n<=2*m){
    13         if(n!=p&&(n%2==p%2)) printf("1
    ");
    14         else if(n==p) printf("%d
    ",m-(n-1)/2);
    15         else printf("0
    ");
    16         return ;
    17     }
    18     else if(n==2*m+1){
    19         if(p<2*m&&(p&1)) printf("1
    ");
    20         else printf("0
    ");
    21         return ;
    22     }
    23     int t=n-2*m;
    24     for(int i=0;i<14;i++){
    25         if(t==f[i]){
    26             printf("0
    ");
    27             return ;
    28         }
    29     }
    30     for(int i=1;i<14;i++){
    31         if(t<f[i]){
    32             if(p>2*m+f[i-1]&&p<2*m+f[i])
    33                 printf("Thrown
    ");
    34             else printf("0
    ");
    35             return ;
    36         }
    37     }
    38 }
    39 int main(){
    40     int n,m,p,t;
    41     I(t);
    42     while(t--){
    43         scanf("%d%d%d",&n,&m,&p);
    44         solve(n,m,p);
    45     }
    46     return 0;
    47 }
    View Code

  • 相关阅读:
    安卓远程工具介绍及下载地址
    kylinos-kysec介绍
    远程控制工具ToDesk介绍
    kylinos桌面和服务器系统重置密码
    APT仓库目录和repository目录结构
    使用LVM实现动态磁盘管理
    如何实现访问http自动跳转https
    TypeScript学习 ———— 四、泛型
    TypeScript学习 ———— 三、function
    TypeScript学习 ———— 二、接口
  • 原文地址:https://www.cnblogs.com/xin-hua/p/3294693.html
Copyright © 2011-2022 走看看