您的位置:首页 > 其它

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

2017-06-08 20:43 302 查看
巴什博弈

一堆   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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法