四种博弈浅谈(巴什博弈、威佐夫博弈、妮姆博奕、斐波那契博弈)

巴什博弈


一堆   n个物品    两人轮流从中取物品    每人至少拿一个  最多拿m个    将这堆物品最后取完的是winner

先手胜利条件-------------   n%(m+1)!=0

谁面对  (m+1)*k  的情况谁就输了(k为正整数)


#include <stdio.h>
int main (){
	int n,m;
	while (scanf("%d%d",&n,&m)!=EOF){
		if (n%(m+1))
			printf ("first is winner\n");
		else
			printf ("second is winner\n");
	}
	return 0;
}

威佐夫博弈


有两堆物品    每堆有若干个     两个人轮流取物品     规定有两种取法

1、从一堆物品中取    至少取一个     没有上限

2、从两堆物品中取相同个数的物品

将这两堆物品最后都取完的是winner


假设两堆物品分别有 [x,y]  

当某人面对(0,0) (1,2) (3,5) (4,7) (6,10) (8,13) (9,15) (11,18) (12,20)。。。。

这个是一定会输(不会证明)

可以发现规律    ai = i*(1+sqrt(5))/2;         yi = ai + i ;  (用到黄金分割数)

所以判断   x  y   是否为奇异点(必败点)     如果是奇异点先手必输

#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
int main (){
	int x,y;
	while (scanf("%d%d",&x,&y)!=EOF){
		if (x>y)
		swap(x,y);
		int tempx=(y-x)*(1+sqrt(5))/2;
		if(tempx==x)
			printf ("second is winner\n");
		else
			printf ("first is winner\n");
	}
	return 0;
}

尼姆博弈


三堆(可以推广到n堆)     每堆若干物品      两人轮流从某一堆中取物品      至少取一个     没有上限      最后将所有物品取完的是winner


假设三堆物品分别有 [x,y,z]

当某人面对 [0,0,0] 这种局面时     这个人一定是输的

当某人面对 [0,n,n] 这种局面时     这个人也是输的

也很好理解   当你面对 [0,n,n] 这种局面时  你从两堆中的某一堆中拿走 k 个      然后你的对手从另一堆中拿走 k 个    一直拿下去  最后面对 [0,0,0] 这种局面的一定是你

当某人面对 [1,2,3] 这种局面时      这个人也是输的

当你面对这种局势时    无论你怎么取     你的对手都能把局势变成 [0,n,n] 这种    例如: 你取走第一堆的 1    然后你的对手就会取走第三堆中的一个    局势变为 [0,2,2]   等等

奇异局势特点     将每堆中物品的个数全部异或之后结果为 0 (尴尬   同样不会证明)

会用到异或的一个小性质      0^x = x        1^x = x'(非x)

#include <stdio.h>
int main (){
    int num;
    int n;
    while (scanf("%d",&n)!=EOF){
        int ans=0;
        for (int i=0;i<n;i++){
            scanf ("%d",&num);
            ans^=num;
        }
        if (ans)
            printf ("first is winner\n");
        else
            printf ("second is winner\n");
    }
    return 0;
}

斐波那契博弈


一堆     若干物品     两人轮流取物品     规定取法: 先手第一次不能把物品取完    每次最少取一个    最多取对手最近一次所取物品的二倍     最后将物品取完的是winner

奇异局势特点     当物品个数是斐波那契数的时候    先手必败  (依然没有证明)

#include <stdio.h>
typedef long long ll;
ll fib[50];
int main (){
    int n;
    fib[0]=1;
    fib[1]=2;
    for (int i=2;i<=50;i++)
        fib[i]=fib[i-1]+fib[i-2];
    while (scanf("%d",&n)!=EOF){
        int flag=1;
        for (int i=0;i<=50&&flag;i++)
            if (fib[i]==n)
                flag=0;
        if (flag)
            printf ("first is winner\n");
        else
            printf ("second is winner\n");
    }
   return 0;
}



阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页