一.巴什博奕(Bash Game)
一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取1 or p个,最多取m个。最后取光者得胜.
eg:m=4
n=4 A必胜
n=5 A 不论先拿了几个,B 都可以一次性把剩下的拿完,A 必输
n=6 A 可以先拿 1 个,然后数量变成了 5 个,此时问题就变成了n=5.B 无论拿几个,A 都可以一次性把剩下的拿完.A必胜.
n=7 8 9 同上
n=10 同n=5 A 必输
n 是(m+1)的倍数,那么 先手者就必输。
验证如下:
如果物品数量 n 可以化成 k(m+1)+ x 的形式(即 n 不可被(m+1)整除)其中 k 为自然数,0 < x < m+1 , 那么只要先手者第一次拿走 x 个物品,剩余物品变为 k(m+1),接下来无论后手者怎么拿,先手者都可以让物品数量变 k(m+1) , k逐渐变小直到最后变为 1 ,此时剩余物品为 m+1 ,接下来无论后手者拿多少都拿不完 ,并且会使剩余物品数量小于 m+1 ,而先手者则可以直接把剩下的拿完。所以先手者必胜。
如果物品数量为 k(m+1)(即 n 可被(m+1)整除)此时先手者就会面临上面的 后手者的问题,所以先手者必输。
#include <iostream>
#include <algorithm>
#include<string>
using namespace std;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n, m;
scanf("%d%d", &n, &m);
if (n % (m + 1) == 0) //后者胜
puts("no");
else
puts("yes"); //前者胜
}
return 0;
}
n= k(m+p)+ x
反巴什博奕:最后取光者输
(n-1)%(m+1)==0 则 后手胜利
二.威佐夫博奕(Wythoff Game)
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
若两堆物品的初始值为(x,y),且x<y,则另z=y-x;
记w=(int)[((sqrt(5)+1)/2)*z ];
若w=x,则先手必败,否则先手必胜。
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int main()
{
int a,b,k,zz;
while(scanf("%d%d",&a,&b)==2){
k=abs(a-b);
a=a<b?a:b;
zz=ceil(k*(1.0+sqrt(5.0))/2);
if(a==zz)
printf("no\n");
else
printf("yes\n");
}
}
三. 尼姆博弈(Nimm Game)
有任意堆物品,每堆物品的个数是任意的,双方轮流从中取物品,每一次只能从一堆物品中取部分或全部物品,最少取一件,取到最后一件物品的人获胜。
结论:把每堆物品数全部异或起来,如果得到的值为0,那么先手必败,否则先手必胜。
第一个类型:就是让其判断胜利的人//最后取完者赢
对n堆石子求异或和,根据当Nim和!= 0时,先手胜利,否则失败就能判断出来。
#include <iostream>
#include <iostream>
#include <algorithm>
#include<string>
using namespace std;
int main()
{
int n;
while (cin>>n&&n)
{
int cnt=0;
int m;
for(int i=1;i<=n;i++)
{
cin>>m;
cnt^=m;
}
if(cnt)cout<<"yes";//先手胜
else cout<<"no";
}
return 0;
}
第二个类型:最后取完者判输//反nim
统计一下所有数一下大于1的个数,并将所有数字异或一遍,若大于1的个数为0&&异或和为0||大于1的个数大于0&&异或和不为零,则先手胜,否则后手胜。
//hdu1907
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
int f=0;
int sum=0;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
if(x>1) f=1;
sum^=x;
}
if((sum&&f)||(!sum&&!f))
puts("John");
else
puts("Brother");
}
return 0;
}
第三个类型:nimk
限制最多取的个数,例如第i堆石子共有m个,最多取r个,先对m=m%(r+1);然后在进行异或求和。再根据异或和判断输赢。
例题:sdnuoj1253
//nimk博弈问题
#include<cstdio>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn = 10005;
int sg[maxn],eor[maxn];
int num,maxx,hy;
bool nimk(int n, int m)
{
memset(eor, 0, sizeof(eor));
maxx = -1;
for(int i=1;i<=n;i++)
{
hy=sg[i];
num=0;
while(hy)
{
eor[num]+=hy&1;
num++;
hy>>=1;
}
maxx=max(maxx,num);
}
for(int i=0;i<maxx;i++)
{
if(eor[i]%(m+1))
return true;
}
return false;
}
int main()
{
int T;
cin >> T;
int cas = 1;
while(T--)
{
memset(sg, 0, sizeof(sg));
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++)
cin >> sg[i];
cout<<"Case #"<<cas<<": ";
if(nimk(n, m))
cout<<"Alice\n";//先手胜
else
cout<<"Bob\n";//后手胜
cas++;
}
return 0;
}
第四种类型:先手的人想赢,第一步有多少种选择。
//hdu1850
#include <iostream>
#include <algorithm>
#include<string>
using namespace std;
int a[1000010];
int main()
{
int n;
while (cin>>n&&n)
{
int cnt=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
cnt^=a[i];
}
int sum=0;
for(int i=1;i<=n;i++)
if((cnt^a[i])<a[i])sum++;
cout<<sum<<'\n';
}
return 0;
}
第五种类型:限制最多取的堆数
问题:有两个绝顶聪明的人在玩取石子游戏,假设有n堆石子,每个人可以轮流在不超过k堆石子中拿走任意数量的石子(不能为0),无法拿石子的一方失败,问先手还是后手胜利。
当且仅当所有堆石子数在二进制下的各位上的1的数目都满足是k+1的倍数的时候是必败局面。//异或取模k+1=0?
借鉴
例题:
台阶(只考虑奇数台阶)
现在,有一个n级台阶的楼梯,每级台阶上都有若干个石子,其中第i级台阶上有ai个石子(i≥1)。
两位玩家轮流操作,每次操作可以从任意一级台阶上拿若干个石子放到下一级台阶中(不能不拿)。
已经拿到地面上的石子不能再拿,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;cin>>n;
int x = 0;
for(int i=1,t;i<=n;i++){
cin>>t;
if(i&1) x^=t;//i&1----i%2==1
}
if(x) cout<<"Yes\n";
else cout<<"No\n";
return 0;
}
借鉴
四. 斐波那契博弈
有一堆物品,两人轮流取物品,先手最少取一个,至多无上限,但不能把物品取完,之后每次取的物品数不能超过上一次(即对手)取的物品数的二倍且至少为一件,取走最后一件物品的人获胜。
结论是:先手胜当且仅当n不是斐波那契数(n为物品总数)
#include <iostream>
#include <stdio.h>
using namespace std;
const int N = 55;
int f[N];
void Init()
{
f[0] = f[1] = 1;
for(int i=2;i<N;i++)
f[i] = f[i-1] + f[i-2];
}
int main()
{
Init();
int n;
while(cin>>n)
{
if(n == 0) break;
bool flag = 0;
for(int i=0;i<N;i++)
{
if(f[i] == n)
{
flag = 1;
break;
}
}
if(flag) puts("Second win");
else puts("First win");
}
return 0;
}
五.贝蒂定理(Betti theorem)//没整明白
设a、b是正无理数且 1/a +1/b =1。记P={ [na] | n为任意的正整数},Q={ [nb] | n 为任意的正整数},([x]'指的是取x的整数部分)则P与Q是Z+的一个划分,即P∩Q为空集且P∪Q为正整数集合Z+。
结论是:Z+=P∪Q。