博弈论专题 kuangbin题单(巴什,威佐夫,nim,fib博弈)+SG函数打表

省赛前先练着,回来补完

巴什博弈: 一堆n个物品两个人来拿,每人至少拿一个,最多拿m个,问最后取完的人win
判断条件:n%(m+1)!=0

cin>> n>>m;
if (n%(m+1)!=0)
	cout<<first win<<endl;
else
	cout<<second win<<endl;

威佐夫博弈:两堆物品a,b,有两个人轮流来取,从一堆中取至少一个没有上限,或者从两堆中取相同数量的物品。两堆最后都取完的人win
判断点:(b-a)*(1+sqrt(5))/2,b为ab中的最大值,

cin>>a>>b;
if(a>b) swap(a,b);
int temp=(b-a)*(1+sqrt(5))/2;
if(temp==a) cout<<second win<<endl;
else cout<<first win<<endl;

nim博弈:有n堆物品每堆数量无限制,两个人从第一堆开始取,每次取至少一个没有上限,最后全取完的人win
判断条件 ans^=num

cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
    
    
	cin>>num;
	ans^=num;
}
if(ans) cout<<first win<<endl;
else cout<<second win<<endl;

fib博弈:一堆若干物品,两人轮流取物品,先手第一次不能把物品取完但后手可以(没必要),每次最少取一个,最多取对手最近一次所取物品的二倍,最后将物品取完的是人win
取法很奇怪应该是特定题目的解法,判断条件是一开始的物品数为斐波那契数则先手必败,打个表取找找就行。

日常贴带佬文章orz

SG函数:记打表公式,根据打表去找规律,寻找sg函数为0的特殊点,原理是拆成部分博弈类似nim博弈
转载大佬bestsort博客orz

//f[N]:可改变当前状态的方式,N为方式的种类,f[N]要在getSG之前先预处理
//SG[]:0~n的SG函数值
//S[]:为x后继状态的集合
int f[N],SG[MAXN],S[MAXN];
void  getSG(int n){
    
    
    int i,j;
    memset(SG,0,sizeof(SG));
    //因为SG[0]始终等于0,所以i从1开始
    for(i = 1; i <= n; i++){
    
    
        //每一次都要将上一状态 的 后继集合 重置
        memset(S,0,sizeof(S));
        for(j = 0; f[j] <= i && j <= N; j++)
            S[SG[i-f[j]]] = 1;  //将后继状态的SG函数值进行标记
        for(j = 0;; j++) if(!S[j]){
    
       //查询当前后继状态SG值中最小的非零值
            SG[i] = j;
            break;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_45891413/article/details/108900179