博弈

一、巴什博弈(Bash Game)

      只有一堆n个物品,两个人从轮流中取出(1~m)个;最后取光者胜

   思路:考虑到 若n=m+1 那么 第一个人不论如何取都不能取胜。

      进一步我们发现 若 n=k*(m+1)+r; 先取者拿走 r 个,那么后者再拿(1~m)个

      n=(k-1)*(m+1)+s; 先取者再拿走s 个 最后总能造成 剩下n=m+1 的局面。

      因此,此时先手有必赢策略。

      相对应的,若n=k*(m+1) 那么先取者必输。

int Bash_Game(int n,int m)//是否先手有必赢策略
{
    if (n%(m+1)!=0) return 1;
    return 0;
}

二、尼姆博弈

  有3堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取1个,多者不限,最后取光者得胜

思路:首先自己想一下,就会发现只要最后剩两堆物品一样多(不为零),第三堆为零,那面对这种局势的一方就必败。

①那我们用(a,b,c)表示某种局势,首先(0,0,0)显然是必败态,无论谁面对(0,0,0) ,都必然失败;

②第二种必败态是(0,n,n),自己在某一堆拿走k(k ≤ n)个物品,不论k为多少,对方只要在另一堆拿走k个物品,最后自己都将面临(0,0,0)的局势,必败。

③仔细分析一下,(1,2,3)也是必败态,无论自己如何拿,接下来对手都可以把局势变为(0,n,n)的情形


那这些奇异局势(必败态)有什么特点呢?

我们要用到位运算当中的异或(XOR)

  • 对于奇异局势(1,2,3):1 XOR 2 XOR 3 = 0;
  • 对于奇异局势(0,n,n)也一样,结果也是0;
  • 任何奇异局势(a,b,c)都有a XOR b XOR c = 0

如果我们面对的是一个非必败态(a,b,c),要如何变为必败态呢?

假设 a < b < c,我们只要将 c 变为a XOR b,即可。因为有如下的运算结果:

a XOR b XOR (a XOR b)=(a XOR a) XOR (b XOR b) = 0 XOR 0 = 0

要将c 变为a XOR b,只要对 c进行 c-(a XOR b)这样的运算即可。

int Nimm_Game(int n)//假设n个数存在数组f[]中,有必胜策略返回1
{
    int flag=0;
    for(int i=1; i<=n; i++)
        flag^=f[i];
    if(flag) return 1;
    return 0;
}

1.尼姆博弈模型可以推广到:有n堆若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

这个游戏中的变量是堆数k和各堆的物品数N1,N2,……,Nk。

对应的组合问题是,确定先手获胜还是后手获胜以及两个游戏人应该如何取物品才能保证自己获胜

2.为了进一步理解Nim取物品游戏,我们看看特殊情况。

如果游戏开始时只有一堆物品,先手则通过取走所有的物品而获胜。现在设有2堆物品,且物品数量分别为N1和N2。游戏者取得胜利并不在于N1和N2的值具体是多少,而是取决于它们是否相等

也就说两堆的策略我们有了,现在我们如何从两堆的取子策略扩展到任意堆数中呢?

首先回忆一下,每个正整数都有对应的一个二进制数,例如:57(10) = 111001(2) ,即:57(10)=2^5+2^4+2^3+2^0。于是,我们可以认为每一堆物品数由2的幂数的子堆组成。这样,含有57枚物品大堆就能看成是分别由数量为2^5、2^4、2^3、2^0的各个子堆组成, 现在考虑各大堆大小分别为N1,N2,……Nk的一般的Nim博弈。将每一个数Ni表示为其二进制数(数的位数相等,不等时在前面补0):

N1 (2#)= as…a1a0

N2 (2#)= bs…b1b0

……

Nk (2#)= ms…m1m0

如果每一种大小的子堆的个数都是偶数,我们就称Nim博弈是平衡的,而对应位相加是偶数的称为平衡位,否则称为非平衡位。因此,Nim博弈是平衡的,当且仅当:

as +bs + … + ms 是偶数,即as XOR bs XOR … XOR ms  = 0

……

a1 +b1 + … + m1 是偶数,即a1 XOR b1 XOR … XOR m1 = 0

a0 +b0 + … + m0是偶数,即a0 XOR b0 XOR … XOR m0 = 0

  

于是,我们就能得出尼姆博弈中先手获胜策略:

Bouton定理:先手能够在非平衡尼姆博弈中取胜,而后手能够在平衡的尼姆博弈中取胜。

三、威佐夫博弈(Wythoff's game)

  有两堆各若干个物品,两个人轮流 从任意一堆中取出至少一个 或者 同时从两堆中取出同样多的物品,规定每次至少取一个,至多不限,最后取光者胜利

结论:假设两堆石子为(x,y)(其中x

那么先手必败,当且仅当

(int)[(y-x)*\frac{(\sqrt{5}+1)}2] = x

其中的(\sqrt{5}+1) / 2实际就是1.618,黄金分割数!

#include
#include
#include
#define int long long 
using namespace std;
main()
{
    int a,b;
    scanf("%lld%lld",&a,&b);
    if(a>b) swap(a,b);
    int temp=abs(a-b);
    int ans=temp*(1.0+sqrt(5.0))/2.0;
    if(ans==a) printf("0");
    else       printf("1");
    return 0;
}

证明:

我们用(a[k],b[k])    (a[k] ≤ b[k] ,k=0,1,2,......n)来表示两堆物品的数量,并且称这个为局势。

首先我们来从最简单的情况开始分析:

1.如果现在的局势是(0,0),很明显此时已经没有办法再取了,所以肯定是之前的人在上一局中取完了。

2.假设现在的局势是(1,2),那么先手只有四种取法。

(1) 如果先手取走“1”中的1个,那么后手就从“2”中取出2个,此时取完,所以后手胜利。

(2)如果先手取走“2”中的2个,那么后手取走“1”中的1个,此时取完,后手胜利。

(3)如果先手取走“2”中的1个,那么后手就在两堆中各取走1个,此时取完,后手胜利。

(4)如果先手在“1”和“2”各取走了1个,那么后手取走“2”中的1个,此时取完,后手胜利。

  由此可得,先手必输。

3.假设现在的局势是(3,5),首先根据上面分析的经验,我们知道先手肯定不能把任意一堆物品取完,这是因为每次可以从任意一堆取走任意个物品,那么后手就可以直接把另一堆取完,所以后手获胜。

所以我们这里就不分析那些情况,来分析其他的情况。

先看在一堆中取的情况:

(1) 假设先手在“3”中取1个,后手就可以在“5”中取走4个,这样就变成了(1,2)的局势,根据上面的分析,我们知道是先手输,后手获胜。

(2) 假设先手在“3”中取2个,后手就可以在 “5” 中取走3个,这样也变成了(1,2)的局势了,还是先手输,后手获胜。

(3)假设先手在“5”中取1个,后手就在 “3”和“5” 中各取走2个,这样又成了(1,2)的局势了,先手输,后手赢。

(4)假设先手在“5”中取2个,后手就在 “3”和“5” 中各取走3个,这样变成了(0,0)的局势,先手输,后手赢。

(5)假设先手在“5”中取3个,后手就在 “3”和“5” 中各取走1个,也变成了(1,2)的局势,先手输,后手胜利。

(6)假设先手在“5”中取4个,后手在“3”中取走1个,还是(1,2)的局势,先手输,后手赢。

我们发现上面列举的这几种局势,无论先手怎么取都是后手赢。


我们可以来找找那些先手必输局势的规律

第一个(0,0)

第二个(1,2)

第三个(3,5)

第四个(4 ,7)

第五个(6,10)

第六个 (8,13)

第七个 ( 9 , 15)

第八个 ( 11 ,18)……

第n个(a[k],b[k])

我们把这些局势称为“奇异局势”,我们会发现他们的差值是递增的,分别是0,1,2,3,4,5,6,7......n,我们用数学方法分析发现这些局势的第一个值是未在前面出现过的最小的自然数。

继续分析我们会发现:每种奇异局势的第一个值总是等于当前局势的差值乘上1.618

0.618是黄金分割率,而威佐夫博弈正好是1.618,即(\sqrt{5}+1 ) / 2,所以……

你可能感兴趣的:(博弈)