一、经典博弈
1.巴什博弈
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.最后取光者得胜
1.1思路:
n = k*(m+1) + r 将n划分为k份(m+1)与一份r,当只剩下m+1个物品时必胜。
1.2必胜策略
先手取r份,随后每一轮与后手取的物品份数总和保持为(m+1)的倍数,最后一轮仅剩m+1时无论后手取多少,先手都可以拿完全部物品,先手必胜。
若r = 0,先手没有必胜策略,后手必胜。
1.3代码实现
bool ns(int n,int m)
{
if(n%(m+1)) return true;//先手必胜
else return false;//后手必胜
}
2.斐波那契博弈
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,至多不限,最后取光者胜
2.1思路:
我们设物品少的那堆物品为a,另一堆为b。
显然,我们取物品时不能将任意一堆取光,否则后手可以之间取光另一堆获胜;也不能让两堆剩余物品数量相同,否则后手仍旧可以取光物品。
当a,b满足下列情况的时:
第一种情况(0,0),无法再取,意味着后手在上一轮取光了物品,后手必胜。
第二种情况(1,2),a取1或者b取2都会让一堆物品取光输掉比赛,b取1则会让两堆数量相等同样输掉比赛,可见第二种情况后手依旧必胜。
第三种情况(3,5),可以发现无论怎么取,要么直接输掉比赛,要么先手取完之后后手可以让情况变成第二种,后手必胜。
......
上述局势中后手必胜,我们称之为“奇异局势”!
可以发现这些“奇异局势”的差值是递增的,分别为 0,1,2,3,4,5,6,7......,而且每个奇异局势的第一个值都是前面没有出现过的最小自然数。
1.2.1后手必胜:
当你先手面临奇异局势时,先手没有必胜策略,后手必胜。
1.2.2先手必胜:
先手遇见非奇异局势,可以通过适当的操作将其变为奇异局势,此时先手必胜。
2.2必胜策略
由上可知,是否先手面临奇异局势是先手能否必胜的关键,而判断奇异局势有一个很便利的手段,那就是黄金分割比。
当abs(a-b) * 黄金分割比 = min(a,b)时,局势为奇异局势。
ps:黄金分割比 = 1.618......
2.3代码实现
bool wg(int a,int b)
{
double r = (sqrt(5.0) + 1)/2;
if(abs(a-b)*r == min(a,b))return false;//后手必胜
else true; //先手必胜
}
3.尼姆博奕
有n堆物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,至多不限,最后取完者胜
3.1思路:
略。
3.2必胜策略
对n堆物品异或和,结果为0则后手必胜,反之则先手必胜 。
3.3代码实现
bool nu(int v[],int n)
{
int res = 0;
for(int i=1;i<=n;i++)
{
res ^= v[i];
}
if(res)return true;//先手必胜
else return false;//后手必胜
}
4.斐波那契博奕
一堆石子有n个,两人轮流取,先手第一次可以取任意多个,但是不能取完,以后每次取的石子数不能超过上次取子数的2倍,取完者胜。
4.1思路:
略。
4.2必胜策略
当n为斐波那契数的时候,先手必败。
4.3代码实现
bool nu(int n)
{
int f[100];
f[0] = f[1] = 1;
for (int i = 0; f[i - 1] < n; i++)
{
if(i>=2)f[i] = f[i - 1] + f[i - 2];
if (f[i] == n) return false;//后手必胜
}
return true;//先手必胜
}