组合游戏--一步一步详细分析理解推导过程

背景:

                •规则:有一堆n个物品,两个人轮流从这堆物品中取物,

                 规定每次至少取一个,最多取m个。

                 两个人足够聪明,最后取光者得胜。

                 问在 n 确定的情况下如何确定两人的胜败情况。

思考过程

              最简单的状态:

              状态(1):n=m+1;先手可取1-m个物品,剩余m-1个物品,所以后手必胜;

             推论:

             状态(2):n=(m+1)+1; 先手只要取1个物品此时转化为状态(1),无论后手取1-m个物品,先手可在第二次取尽,所以先手必胜;(注意状态转化是先后手改变)

            状态(3):n=(m+1)+s;先手只要取m个物品即可转化为状态(1),状态(1)结果已知,可直接使用结果推出先手必胜

            总结状态(2)(3):

            状态(4):n=(m+1)+s;(1<=s<=m); 此时先手只要取s个物品即可转化为状态(1),先手必胜;

             状态(5):n=2(m+1);此时无论先手取1-m个,都会转化为转态(4),后手必胜

            状态(6):n=2(m+1)+s;此时先手只要取s个物品即可转化为状态(5),先手必胜

            状态(7):n=3(m+1);此时无论先手取1-m个都会转化为状态(6),后手必胜

            状态(8):n=3(m+1)+s;此时先手只要取s个则转化为状态(7),先手必胜

         归纳:

          当n=k(m+1)+s时,k=任意自然数,;(1<=s<=m);先手每次只要取掉si个,保证每次给后手留下(m+1)的整数倍,则可必胜;

         当n=k(m+1)时,后手必胜;

必胜必败态理论:
   
所有终结点是必败点
   
规则1:一个状态是必败的状态,当且仅当它的所有后继状态为必胜状态
   
规则2:一个状态是必胜的状态,当且仅当它的所有后继状态中至少有一个是必败状态

应用例题:

Ferguson游戏:
   
进行游戏需要用到两个盒子,在游戏的开始,第一个盒子中有n枚石子,第二个盒子中有m个石子(n, m > 0,n+m<20)。参与游戏的两名玩家轮流执行这样的操作:清空一个盒子中的石子,然后从另一个盒子中拿若干石子到被清空的盒子中(至少一个),使得最后两个盒子都不空。当两个盒子中都只有一枚石子时,游戏结束。最后成功执行操作的玩家获胜。终态为[1,1]

根据必胜必败态理论,[1,1]为必败态,所有只要能推出一个必败态([1,1])的状态为必胜态,所有能推出的子状态都是必胜态的状态为必败态。

代码解:

#include <iostream>  
using namespace std;  
#define maxn 100  

int main(){
    bool win[20][20];//win[i][j]记录状态(i,j)是否为必胜态;
    win[1][1]=false;//终态(1,1)为必败态;
    //将所有状态循环一遍
    //因为要将状态(n,m)的子状态全部判断一遍,所以要保证(n,m)的子状态已经全部被判断过
    //注意观察状态(n,m)的子状态的特点,一种为i+j=n,一种为i+j=m;
    //所以循环时应用n+m的和k做循环条件,从小到大,k最小为2,只有一种状态且已知结果,k为三时子状态的和为2,全部已知结果,k为4时,子状态和为3,2,全部已知结果
    //(感觉有点可以类比广度优先或层序遍历的思想呢) 

//{动态规划中的自底向上求解子问题}
    for(int k=3;k<20;k++){
        for(int n=1;n<k;n++){
            int m=k-n;
            win[n][m]=false;//假设(i,j)为必败态;因为必胜态只要有一个子状态为必败态就可判断,比较好判断;而必败态需要所有子状态都为必胜态,比较难做出判断 ;所以这里我们假设为必败态,去判断是不是必胜态;
        //将(n,m)的所有子状态循环一遍;
            for(int i=1;i<n;i++){//第一种子状态的和做循环终止条件
                if(!win[n-i][i]){//若有一子状态(n-i,i)为必败态
                    win[n][m]=true;// 则(n,m)为必胜态
                    break;
                }
            }
            for(int i=1;i<m;i++) {//同理,第二种
                if(!win[i][m-i]){//若有一子状态(i,m-i)为必败态
                    win[n][m]=true;// 则(n,m)为必胜态
                    break;
                }
            }
           // if(n<m&&win[n][m]==false)cout<<"("<<n<<","<<m<<")"<<endl;//(n,m)(m,n)视为同种状态
            //注意,有n<m和n=m两种
             if(n<=m&&win[n][m]==false)cout<<"("<<n<<","<<m<<")"<<endl;
       }
    }
    
    return 0;
}

时间上应该还可以继续优化


2.巴什博弈:
   
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。
   
显然,因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。


   

    对于巴什博奕,那么我们规定,如果最后取光者输,那么又会如何呢?
   
        (n-1)%(m+1)==0则后手胜利
先手会重新决定策略,所以不是简单的相反行的

   最简单的状态:n=1;先手必败

   (1)n=1+s,(1<=s<=m);先手只要取s个,后手必败,先手必胜

   (2)n=1+(m+1);无论先手取1-m个,都变为状态(1),先手必败;

   (3)n=1+(m+1)+s;先手取s个,变为(2),先手必胜;

   (4)n=1+2(m+1);无论先手取1-m个都变为(3),先手必败;

   (5)n=1+2(m+1)+s;先手取s个变为(4),先手必胜;

   (6)n=1+3(m+1);无论先手取1-m个变为(5),先手必败;

    归纳 n=1+k(m+1)(k=任意自然数),先手必败;//所以有(n-1)%(m+1)==0,后手必胜。

            n=1+k(m+1)+s;先手必胜;

    


·nim游戏

 要知道,像Nim游戏这种博弈问题,最重要的是寻找必败态。这个必败态的的意思就是,这样一种局面摆在面前的话先手必败。其严格定义如下:1.无法进行任何移动的局面是必败态;2.可以移动到必败态的局面是非必败态;3.在必败态做的所有操作的结果都是非必败态。这个还是很好理解的吧,就是自己处在非必败态上总能移动到必败态把必败态留给对方,而对方处在必败态的话总是只能移动到非必败态,把非必败态留给自己,然后自己继续虐对方。

而对于Nim游戏,局面是必败态当且仅当所有堆硬币的数量都异或起来结果为0,即a1^a2^...^an=0!!!为了证明之,我们只要证明它满足上述必败态的三条性质即可。

第一个命题显然,最终局面只有一个,就是全0,异或仍然是0。

第二个命题,对于某个局面(a1,a2,...,an),若a1^a2^...^an!=0(不等号就用C++的习惯用!=来表示了),一定存在某个合法的移动,将ai改变成ai'后满足a1^a2^...^ai'^...^an=0。不妨设a1^a2^...^an=k,则一定存在某个ai,它的二进制表示在k的最高位上是1(否则k的最高位那个1是怎么得到的)。这时ai^k<ai一定成立。则我们可以将ai改变成ai'=ai^k,此时a1^a2^...^ai'^...^an=a1^a2^...^an^k=0。

第三个命题,对于某个局面(a1,a2,...,an),若a1^a2^...^an=0,一定不存在某个合法的移动,将ai改变成ai'后满足a1^a2^...^ai'^...^an=0。因为异或运算满足消去率,由a1^a2^...^an=a1^a2^...^ai'^...^an可以得到ai=ai'。所以将ai改变成ai'不是一个合法的移动。证毕。

就这样,一个简单而神奇的运算,就搞定了这么个让我绞尽脑汁也毫无头绪的游戏,而Xor运算的出现,又是乍一看完全与问题毫不相干!这正是Xor的奇妙之处,吸引人之处。

”--http://www.physixfan.com/archives/563


PS:正在研读理解组合游戏的问题,顺便整理保留思路,欢迎批评更正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值