巴什博弈
一堆 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;
}