这两天主要在看关于博弈论的内容,总的来说有的巴什博奕,威左夫博弈,尼姆博弈,斐波那契博弈等。最后还有最经典的组合博弈。可能是我比较笨,关于尼姆博弈及其SG函数还没完全看明白。就先整理一下看懂的吧。
1,巴什博奕
来自:http://blog.csdn.net/xuzengqiang/article/details/7763635
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。
显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。因此我们发现了如何取胜的法则:如果
n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。那么这个时候只要n%(m+1)!=0,先取者一定获胜。
这个游戏还可以有一种变相的玩法:两个人轮流报数,每次至少报一个,最多报十个,谁能报到100者胜。
分析此类问题主要放法是:P/N分析:
P点:即必败点,某玩家位于此点,只要对方无失误,则必败;
N点:即必胜点,某玩家位于此点,只要自己无失误,则必胜。
三个定理:
一、所有终结点都是必败点P(上游戏中,轮到谁拿牌,还剩0张牌的时候,此人就输了,因为无牌可取);
二、所有一步能走到必败点P的就是N点;
三、通过一步操作只能到N点的就是P点;
这个是比较好理解的,包括m+1倍的设置恰巧保证的胜利。
2,斐波那契博弈
首先,说明下任何一个正整数都可以被分解为若干斐波那契数和
来自:http://blog.csdn.net/acdreamers/article/details/8586135
题意:
一堆石子有n个,两人轮流取,先取者第1次可以取任意多个,但不能全部取完,以后每次取的石子数不能超过上次取子数的
2倍。取完者胜.先取者负输出"Second win".先取者胜输出"First win"。
比如,我们要分解83,注意到83被夹在55和89之间,于是把83可以写成83=55+28;然后再想办法分解28,28被夹在21和
34之间,于是28=21+7;依此类推 7=5+2,故83=55+21+5+2。
如果 n 是 Fibonacci 数,比如 n = 89。89前面的两个Fibonacci 数是34和55。如果先手第一次取的石子不小于34
颗,那么一定后手赢,因为 89 - 34 = 55 = 34 + 21 < 2*34,注意55是Fibonacci数。此时后手只要将剩下的全部
取光即可,此时先手必败。故只需要考虑先手第一次取得石子数 < 34 即可,于是剩下的石子数 x 介于 55 到 89 之
间,它一定不是一个 Fibonacci 数。于是我们把 x 分解成 Fibonacci 数:x = 55 + f[i] + … + f[j],其中
55 > f[i] > … > f[j],如果 f[j] ≤ 先手一开始所取石子数 y 的两倍,那么对后手就是面临 x 局面的先手,所以
根据之前的分析,后手只要先取 f[j] 个即可,以后再按之前的分析就可保证必胜。
下证:f[j] ≤ 2y
反证法:假设f[j]>2y,则 y < f[j]/2 = (f[j-1] + f[j-2])/2 < f[j-1]。而最初的石子数是个斐波那契数,即
n = f[k] = x + y < f[k-1] + f[i] + … + f[j] + f[j-1] ≤ f[k-1]+f[i]+f[i-1] ≤ f[k-1]+f[k-2] ≤
f[k] (注意第一个不等号是严格的),矛盾!f[j] ≤ 2y得证。
像83=55+21+5+2,先手取走2,后手取得数就不可能把5取走,导致先手再取走剩下的5后还保证后手继续无法取走21,依次耗下去就可以先手必胜。
3威左夫博弈
问题:首先有两堆石子,博弈双方每次可以取一堆石子中的任意个,不能不取,或者取两堆石子中的相同个。先取完者赢。
beatty定理:对于任意满足1/a+1/b=1, 的正无理数a,b,都有结论:[a],[2a],[3a],[4a]......[b],[2b],[3b],[4b]......都是不同的数,而且覆盖正整数集。
推荐:http://www.cnblogs.com/jiangjun/archive/2012/10/25/2740194.html
我就不搬大佬的博客了吧,包括定理证明和推导都很详细,反正就是,综上所述,取a=(sqrt(5)+1)/2,b=(sqrt(5)+3)/2,那么([ak],b[k])(k=1,2,3,4......)就是所有的负态。
int main()
{
double Au = (sqrt(5) + 1) / 2;
int n, m, d;
while (cin >> n >> m)
{
if(n>m) swap(n,m);
cout << (n != int((m - n)*Au)) << endl;//具体证明在大佬的博客里
}
return 0;
}
就先整理到这吧,明天结束尼姆博弈及其sg函数的部分。然后看博客尤其是组合博弈。
必须继续加快速度!!!