一、巴什博奕(同余理论)
一堆物品 n个 每人能取出1~m个 甲先拿 乙后拿
若n=m+1 乙胜
若n=k*(m+1) 乙胜
若n=k*(m+1)+r 甲胜
1.#include<iostream>
2.using namespace std;
3.int main()
4.{
5. int cas,total,price;
6. scanf("%d",&cas);
7. while(cas--)
8. {
9. scanf("%d%d",&total,&price);
10. if(total%(price+1))
11. cout<<"先手赢"<<endl;
12. else
13. cout<<"先手输"<<endl;
14. }
15. return 0;
16.}
二、威佐夫博弈(黄金分割)
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
首先介绍一下奇异局势。
甲乙来拿石子,我们用(ak,bk)(ak ≤ bk ,k=0,1,2,…,n)表示两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲已经输了,这种局势我们称为奇异局势。前几个奇异局势是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)。
可以看出,a0=b0=0,ak是未在前面出现过的最小自然数,而 bk= ak + k。
奇异局势的性质有三条:
1.任何自然数都包含在一个且仅有一个奇异局势中。
2.任意操作可将奇异局势转变为非奇异局势。
3.可以采取操作将非奇异局势转变为奇异局势。
所以威佐夫博弈中必赢一方的理论就是始终让对手面对必输局(奇异局)。
结论:
面对非奇异局势,先拿者必胜;面对奇异局势,后拿者必胜。
奇异局势判断方法:
求出两个石子堆的差值,判断差值与黄金分割率的乘积是否与大的石子堆数目相等。
方法证明:
ak =[k(1+√5)/2]→方括号表示取整函数,bk= ak + k (k=0,1,2,…n )
奇妙的是其中出现了黄金分割数(1+√5)/2 = 1.618…,因此,由ak,bk组成的矩形近似为黄金矩形,由于2/(1+√5)=(√5-1)/2,可以先求出j=[a(√5-1)/2],若a=[j(1+√5)/2],那么a = aj,bj = aj + j,若不等于,那么a = aj+1,b = aj + j + 1,若都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇到奇异局势。
bool Wythoff(int n,int m)//两堆石子数目
{
if(n<m) swap(n,m);
int k=n-m;
n=(int)(k*(1+sqrt(5))/2.0);
if(n==m)
return 0;
else
return 1;
}
三、尼姆博弈(异或原理)
定义P-position和N-position,其中P代表Previous,N代表Next。
上一次move的人有必胜策略的局面是P- position,也就是“后手可保证必胜”或者“先手必败”,
现在轮到move的人有必胜策略的局面是N-position,也就是“先手可保证必胜”。
更严谨的定义是:
1.无法进行任何移动的局面(也就是terminal position)是P-position;
2.可以移动到P-position的局面是N-position;
3.所有移动都导致N-position 的局面是P-position。
所以 可以来画P-N图,然后找规律,比如 hdu2147
对于一个Nim游戏的局面(a1,a2,…,an),它是P-position当且仅当a1^a2^…^an=0,其中^表示异或(xor)运算。
判断方法:
对每堆石子数异或,如果异或为0,先手输;否则,后手输。
四、斐波那契博弈
讲的蛮好
参考博客:
简洁明了
题目与知识点相结合
值得多啃几遍的SG函数
ps:感觉这几天整个机房都在学博弈○| ̄|_