博弈基础小结
巴什博弈
一堆n个物品,两个人轮流取1~m个,最后一个取光的人胜利
if(n%(m+1)) return false;
else return true;
wythoff博弈
两堆各若干个物品,两人轮流从一堆中取走至少一个,或者从两堆中取走相同数量的物品,最后一个取光的人胜利
差值 * 黄金分割比 == 最小值时后手赢,否则先手赢
double r = (sqrt(5.0)+1) / 2;
int d = abs(a-b) * r;
if( d != min(a,b) ) return true;
else return false;
尼姆博弈
n堆物品,两人轮流取至少一个,最后一个取光的人胜利
int res = 0;
for(int i=1;i<=n;i++){
res = res ^ a[i];
}
if(res) return true;
else return false;
SG函数
hdu1848,斐波那契堆
#include <iostream>
#include <string.h>
#define MAXN 3010
using namespace std;
int f[MAXN], sg[MAXN];
void init(){//得到1000以内的fibonacci数列
f[1]=1;
f[2]=2;
for(int i=3; ; i++){
f[i]=f[i-1]+f[i-2];
if(f[i]>1000){
break;
}
}
}
void get_sg(){//sg函数打表
for(int i=1; i<=1000; i++){
int vis[MAXN];
memset(vis, 0, sizeof(vis));
for(int j=1; f[j]<=i; j++){//找到当前节点能到达的点
vis[sg[i-f[j]]]=1;
}
for(int j=0; j<=1000; j++){//求mex函数
if(!vis[j]){
sg[i]=j;
break;
}
}
}
}
int main(void){
init();
get_sg();
int n, m, p;
while(cin >> n >> m >> p){
if(n+m+p==0){
break;
}
if(sg[n]^sg[m]^sg[p]){//sg函数性质
cout << "Fibo" << endl;
}else{
cout << "Nacci" << endl;
}
}
return 0;
}
hdu1847,二的幂次
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int a[20];
int sg[maxn+5];
int n;
int vis[maxn+5];
//sg[1] == 0 //必胜局
//sg[2] == 0 //必胜局
void getSg(){
memset(sg,0,sizeof(sg));
for(int i=1;i<=maxn;i++){
//寻找每一个i的sg值
memset(vis,0,sizeof(vis));
for(int j=0;j<11;j++){ //枚举可以拿的数量("能拿"说明比当前拥有的数量i小)
int temp = i - a[j];
if(temp < 0 )break;
vis[sg[temp]] = 1;//可以由temp这个局面推出来
}
for(int j=0;j<maxn;j++){
if(vis[j] == 0){
sg[i] = j;//sg值为 mex集合中最小的值
break;
}
}
}
}
int main(){
a[0] = 1;
for(int i=1;i<11;i++){
a[i] = a[i-1]*2;//可以拿的数量 打表
}
getSg();
int n;
while(cin>>n){
if(sg[n]) puts("Kiki");
else puts("Cici");
}
return 0;
}
记忆化搜索的递归写法:
memset(sg,-1,sizeof(sg));
int mex(int x){
if(sg[x] != -1) return sg[x];
bool vis[1200];
memset(vis,false,sizeof(vis));
for(int i=0;i<11;i++){
int temp = x - a[i];
if(temp < 0) break;
sg[temp] = mex(temp); //mex:mex操作的含义找到集合中最小的元素
vis[sg[temp]] = true; //标记为集合中有的
}
for(int i=0;;i++){
if(!vis[i]){
sg[x] = i;
break;
}
}
return sg[x];
}