首先要明确明白博弈的基本思路是要寻找必败点与必胜点
必胜点:在这一点轮到我那我赢定了。性质:从必胜点出发一定会走到至少一个必败点(我在这里必胜是因为我走一步一定能让我的对手必败)。
必败点:我走到这一点我输定了。性质:从必败点出发前方全是必胜点(即我在必败点无论怎么走都是对面的必胜点)。
例1:15张牌,每次只能取1、3、4张牌,谁赢?
画表:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
P N P N N N N P N P N N N N P N
P表示必败点,N表示必胜点
简单例题:Hdoj-1847
AC-代码
#include<iostream>
#include<vector>
#include<map>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<stack>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
const int N = 1005;
int a[N];
int b[20];
int main()
{
int n;
b[0] = 1;
for(int i=1;i<11;i++)
b[i] = b[i-1]*2;//1000以内所有2的次幂
while(scanf("%d",&n)==1){
for(int i=1;i<=n;i++)
for(int j=0;b[j]<=i;j++){
if(a[i-b[j]]==0){//一个个减,减出来有必败点标记为必胜点
a[i] = 1;
break;
}
}
if(a[n]==1) printf("Kiki\n");
else printf("Cici\n");
}
return 0;
}
另一种问题:三堆里面或很多堆里面取。
必胜点是多堆数字异或非0的点
必败点是多堆数字异或为0的点
数字异或成为nim-sum,这也叫做nim-sum算法
可以用最后结果000来理解这一算法
例题:hdu1848 Fibonacci again and again
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define M 1050
int k,fibo[M],f[M];
int mex1(int p){
int i,t,g[M]={0};//把g数组全部置0
for(i=0;i<k;i++){//遍历前面所能走到的所有位置
t=p-fibo[i];
if(t<0)break;
g[f[t]]=1;//能走到的标记为1
}
for(i=0;;i++){
if(!g[i])return i;//返回从0开始未访问过的第一个值
}
}
int main()
{
int m,n,p,i,ans;
fibo[0]=1,fibo[1]=2,i=1;
while(fibo[i]<1050){
fibo[i+1]=fibo[i-1]+fibo[i];
i++;
}
k=i;//斐波拉及数的个数
memset(f,-1,sizeof(f));
f[0]=0;
for(i=1;i<=1000;i++){
f[i]=mex1(i);//算出每个数的值
}
while(scanf("%d%d%d",&m,&n,&p)!=EOF&&m+n+p){
ans=0;
ans^=f[m];ans^=f[n];ans^=f[p];//三个堆的nim-sum(异或)
if(ans)printf("Fibo\n");
else printf("Nacci\n");
}
return 0;
}
最后看一个例题:HDU 1849 Rabbit and Grass
#include<iostream>
#include<vector>
#include<map>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<stack>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
const int N = 1005;
int a[N];
int main()
{
int n;
while(scanf("%d",&n)&&n!=0){
int ans = 0;
int temp;
for(int i=0;i<n;i++){
scanf("%d",&temp);
ans^=temp;
}
if(ans) printf("Rabbit Win!\n");
else printf("Grass Win!\n");
}
return 0;
}