对此博文的简述:大牛博客
(一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规
定每次至少取一个,最多取m个。最后取光者得胜。
总结:设n=k*(m+1)+s,如果s==0,则先手输,s!=0,则先手赢
代码:
int Bash_Game(int n,int m){//判断先手输赢(1为赢)
if(n%(m+1)) return 1;
return 0;
}
(二)威佐夫博奕(Wythoff Game):有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
总结:分析到此已经很明显,判断谁个能够胜利看是否是奇异矩阵就行了,如果是奇异矩阵,则后取者胜利,如果是非奇异矩阵,则先取者得胜!在判断是不是咸佐夫博弈的奇异局势的时候,比如两个数a,b,则可以首先交换是a<b,然后记i=b-a,如果是奇异局势,则必有m=floor(i*(1+sqrt(5.0))/2),并且b=m+i,否则比不是奇异局势!
代码:
int Wythoff_Game(int a,int b){
if(a>b) swap(a,b);//交换a,b
int m=(int)(b-a)*(1+sqrt(5.0))/2;
if(m==a) return 0;
return 1;
}
(三)尼姆博奕(Nimm Game):有三堆各若干个物品,两个人轮流从某一堆取任意多的
物品,规定每次至少取一个,多者不限,最后取光者得胜。
总结:面对奇异局势,先取者必定输,如果是非奇异局势,则先取者赢!如果一个局势(a,b,c)有a(+)b(+)c==0,则是奇异局势,如果不是,则不是奇异局势!
int Nimm_Game(int n){)//假设n个数存在数组arr[]中,有必胜策略返回1
int falg=0;
for(int i=0;i<n;i++)
flag^=arr[i];
return flag;
}
(四)SG值求法
有n堆石子,每次从一堆石子中取a到b颗,或者不连续的颗数,但不能不取
判断获胜情况用SG值法。
(HDU1847)代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N = 1010;
int sg[N],f[11];
int vis[N];
void getSG(int n){
memset(sg,0,sizeof(sg));
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
for(int j=0;f[j]<=i;j++)
vis[sg[i-f[j]]]=1;
for(int j=0;j<=n;j++){
if(!vis[j]){
sg[i]=j;
break;
}
}
}
}
int main(){
int n;
for(int i=0;i<=10;i++) f[i]=(1<<i);
getSG(1000);
while(scanf("%d",&n)!=EOF&&n){
if(sg[n]) printf("Kiki\n"); //先手胜
else printf("Cici\n");
}
return 0;
}
(五)斐波那契博弈
有一堆个数为 n 的石子,游戏双方轮流取石子,满足:
1. 先手不能在第一次把所有的石子取完;
2. 之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。
约定取走最后一个石子的人为赢家,求必败态。
当石子数n为斐波那契数时先手输;
例如:HDU2516