nim取子游戏
问题描述:
有k堆石子,两个人I,II分别轮流取子。
一次可以从一堆中至少取一个,至多取完。
最后一个取完的胜利。
问I先手,是否有必胜的策略。
==========================================================================
先考虑个简单的2堆石子。
如果两个石子数量不同,I先取使得两堆数量相同。然后I就模仿II的取法在另一堆取。
这样I就必胜。
若相同,那么II模仿I的取法,II必胜。
如果是k堆呢?
我们来考虑每堆石子的表示方法,用二进制表示之。
因为二进制可以表示任何数。
和刚才两堆类似。
如果所有堆的相同二进制位的1的个数都是偶数,那么肯定II必胜。
如果不满足上面这种情况,那么I必胜。
因为I可以通过一次取子,让其满足此种情况。
如
k = 4
分别是 7 9 12
二进制表示
0111
1001
1100
1111
每位的1的数量
3323,显然是不满足的,所以I必胜。
I的策略就是在15个的上面取
1101个。。。(1101)2=13个
那么就变成了
0111
1001
1100
0010
那样,这时轮到II取,这时无论II怎么取,我们都可以一直让此状态保持平衡。
那么这样到最后还是I赢。
==========================================================================
nim取子游戏就这样了。。呵呵~~
编程也很简单的。
因为每一位个相同位1的个数是偶数,那么我把所有数异或之后肯定就得到的是0。。。
如果非0那么I赢。
阶梯博弈
首先介绍一下阶梯博弈:
//hdu1907 三堆取子,最后取完者输
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 50
int main(){
int t,n,cont[MAX],ans,k;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
k=0,ans=0;
for(int i=0;i<n;i++){
scanf("%d",&cont[i]);
if(cont[i]==1){
k++;
}
ans^=cont[i];
}
if(k==n){
if(k&1){
printf("Brother\n");
}
else{
printf("John\n");
}
}else
if(ans){
printf("John\n");
}
else
{
printf("Brother\n");
}
}
return 0;
}