巴什博弈 (bash game)
题型
仅有一堆n个物品,两我的轮流取1~m个,最后取的人胜(不能取的人输)html
分析
整体可分几种状况数组
- $n=0$,先手输
- $0<n<=m$,先手胜
- $n=m+1$,先手输
- $n=k*(m+1)+r$,先手胜(先手取走r个,给后手留下k*(m+1)的局面)
- $n=k*(m+1)$,先手输
代码
int Bash_Game(int n,int m) //是否先手有必赢策略
{
if(n==0) return 0;
if(n%(m+1)!=0) return 1;
return 0;
}
尼姆博弈(Nim Game)
题型
将一堆变为多堆;
即:
有3堆各若干个物品,两我的轮流从某一堆取任意多的物品,规定每次至少取1个,多者不限,最后取光者得胜。bash
分析
本部分含其余博客内容markdown
地址:https://www.cnblogs.com/jiangjun/archive/2012/11/01/2749937.htmlapp
- 首先本身想一下,就会发现只要最后剩两堆物品同样多(不为零),第三堆为零,那面对这种局势的一方就必败
- 那咱们用(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)的情形
- 那这种奇异局势有什么特色呢?
也不知谁这么牛逼,居然能把这种局势和二进制联系在一块儿
这里说一种运算符号,异或’^’,a^b=a’b+ab’(a’为非a)
咱们用符号XOR表示这种运算,这种运算和通常加法不一样的一点是1 XOR 1 = 0。先看(1,2,3)的按位模2加的结果:
1 = 二进制01
2 = 二进制10
3 = 二进制11 XOR
———————
0 = 二进制00 (注意不进位)
- 对于奇异局势(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)这样的运算便可
-
尼姆博弈模型能够推广到:有n堆若干个物品,两我的轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
这个游戏中的变量是堆数k和各堆的物品数N1,N2,……,Nk。
对应的组合问题是,肯定先手获胜仍是后手获胜以及两个游戏人应该如何取物品才能保证本身获胜
spa
-
为了进一步理解Nim取物品游戏,咱们看看特殊状况。
若是游戏开始时只有一堆物品,先手则经过取走全部的物品而获胜。如今设有2堆物品,且物品数量分别为N1和N2。游戏者取得胜利并不在于N1和N2的值具体是多少,而是取决于它们是否相等。code
- 也就说两堆的策略咱们有了,如今咱们如何从两堆的取子策略扩展到任意堆数中呢?
- 首先回忆一下,每一个正整数都有对应的一个二进制数,例如:57(10) = 111001(2) ,即:57(10)=25+24+23+20。因而,咱们能够认为每一堆物品数由2的幂数的子堆组成。这样,含有57枚物品大堆就能当作是分别由数量为2五、2四、2三、20的各个子堆组成
- 如今考虑各大堆大小分别为N1,N2,……Nk的通常的Nim博弈。将每个数Ni表示为其二进制数(数的位数相等,不等时在前面补0):
N1 = as…a1a0
N2 = bs…b1b0
……
Nk = 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定理:先手可以在非平衡尼姆博弈中取胜,然后手可以在平衡的尼姆博弈中取胜。即状态(x1, x2, x3, …, xn)为P状态当且仅当x1 xor x2 xor x3 xor … xor xn =0。这样的操做也称为Nim和(Nim Sum)
咱们以一个两堆物品的尼姆博弈做为试验。设游戏开始时游戏处于非平衡状态。这样,先手就能经过一种取子方式使得他取子后留给后手的是一个平衡状态下的游戏,接着不管后手如何取子,再留给先手的必定是一个非平衡状态游戏,如此反复进行,当后手在最后一次平衡状态下取子后,先手便能一次性取走全部的物品而获胜。而若是游戏开始时游戏牌平衡状态,那根据上述方式取子,最终后手能获胜
- 下面应用此获胜策略来考虑4堆的Nim博弈。其中各堆的大小分别为7,9,12,15枚硬币。用二进制表示各数分别为:0111,1001,1100和1111
因而可获得以下一表:
|
$2^{3}=8$ |
$2^{2}=4$ |
$2^{1}=2$ |
$2^{0}=1$ |
大小为7的堆 |
0 |
1 |
1 |
1 |
大小为9的堆 |
1 |
0 |
0 |
1 |
大小为12的堆 |
1 |
1 |
0 |
0 |
大小为15的堆 |
1 |
1 |
1 |
1 |
由Nim博弈的平衡条件可知,此游戏是一个非平衡状态的Nim博弈,所以,先手在按获胜策略必定可以取得最终的胜利。具体作法有多种,先手能够从大小为12的堆中取走11枚硬币,使得游戏达到平衡(以下表)htm
|
$2^{3}=8$ |
$2^{2}=4$ |
$2^{1}=2$ |
$2^{0}=1$ |
大小为7的堆 |
0 |
1 |
1 |
1 |
大小为9的堆 |
1 |
0 |
0 |
1 |
大小为12的堆 |
0 |
0 |
0 |
1 |
大小为15的堆 |
1 |
1 |
1 |
1 |
以后,不管后手如何取子,先手在取子后仍使得游戏达到平衡
一样的道理,先手也能够选择大小为9的堆并取走5枚硬币而剩下4枚,或者,先手从大小为15的堆中取走13枚而留下2枚blog
- 归根结底, Nim博弈的关键在于游戏开始时游戏处于何种状态(平衡或非平衡)和先手是否可以按照取子游戏的获胜策略来进行游戏
代码
int Nimm_Game(int n) //假设n个数存在数组f[]中,有必胜策略返回1
{
int sum=0;
for(int i=1;i<=n;i++)
sum^=f[i];
if(sum) return 1;
return 0;
}