一年在外 父母时刻牵挂
春节回家 你能做几天好孩子吗
寒假里尝试做做下面的事情吧
陪妈妈逛一次菜场
悄悄给爸爸买个小礼物
主动地 强烈地 要求洗一次碗
某一天早起 给爸妈用心地做回早餐
如果愿意 你还可以和爸妈说
咱们玩个小游戏吧 ACM课上学的呢~
下面是一个二人小游戏:桌子上有M堆扑克牌;每堆牌的数量分别为Ni(i=1…M);两人轮流进行;每走一步可以任意选择一堆并取走其中的任意张牌;桌子上的扑克全部取光,则游戏结束;最后一次取牌的人为胜者。
现在我们不想研究到底先手为胜还是为负,我只想问大家:
——“先手的人如果想赢,第一步有几种选择呢?”Input
输入数据包含多个测试用例,每个测试用例占2行,首先一行包含一个整数M(1<M<=100),表示扑克牌的堆数,紧接着一行包含M个整数Ni(1<=Ni<=1000000,i=1…M),分别表示M堆扑克的数量。M为0则表示输入数据的结束。
Output
如果先手的人能赢,请输出他第一步可行的方案数,否则请输出0,每个实例的输出占一行。
Sample Input
3 5 7 9 0
Sample Output
1
思路:一个基础的Nim博弈,首先我们要知道一个东西就是a1^a2^a3....an=0的话那么先手必败,
若a1^a2^...^an!=0,一定存在某个合法的移动,将ai改变成ai'后满足a1^a2^...^ai'^...^an=0。若a1^a2^...^an=k,则一定存在某个ai,它的二进制 表示在k的最高位上是1(否则k的最高位那个1是怎么得到的)。这时ai^k<ai一定成立。则我们可以将ai改变成ai'=ai^k,那么最后^起来还是为0
#include<iostream>
#include<cstdio>
using namespace std;
const int N=105;
int a[N];
int main(){
int n,temp=0,cnt;
while(cin>>n&&n){
cnt=0;
temp=0;
for(int i=0;i<n;i++){
cin>>a[i];
temp^=a[i];
}
for(int i=0;i<n;i++){
int t=a[i]^temp;
if(a[i]>t) cnt++;//该堆石子在二进制的最高位上
}
cout<<cnt<<endl;
}
return 0;
}
常见博弈总结:
1.Nim博弈
n堆石子,两人轮流取,只能在一堆中取,规定每次至少取一个,最多取一堆,最后取完者获胜
用0与每个数异或,如最后结果为0,则后手胜
- 设一数组a[m],令sum=0
- 循环与数组每一个数据异或(sum^=a[i])
- sum最后等于0则后手胜
0异或各堆物品,结果为零————后手胜
//a[m]每堆物品的数量 sum=0
int Nimm_Game(int m)
{
for(int i=0;i<m;i++)
sum = sum ^ a[i];
if(sum == 0)
return 0;
return 1;
}
2.巴什博弈
只有一堆n个物品,两个人A,B轮流从这堆物品中取物,规定每次至少取一个,最多取m个,取最后一个物品的人得胜
分析:
- 当 n = m + 1 时,第一个人不可能获胜;
- 当 n = k*(m + 1) + r 时,先取者拿走 r 个,那么后者再拿(1~m)个 , 此时 n =(k-1)*(m+1)+s先取者再拿走s 个 最后总能造成 剩下n=m+1 的局面
- 若n=k*(m+1) 那么先取者必输
int Bash_Game(int n,int m)
{
if (n%(m+1)==0) //后手胜
return 0;
return 1;
}
3.威佐夫博弈
两堆各有若干个物品,两人轮流从某一堆中任意取或者同时从两堆中取同样多的物品,最后取光着胜
- 两堆石子的状态为 [ak,bk] (满足ak<=bk)
- 当 ak=(k*(√5+1)/2), bk=ak+k 时满足奇异局势,那么则先手输,反之则先手赢
若(大-小)*(1+sqrt(5))/2==小————后手胜
t=(max(n,m)-min(n,m))*(1+sqrt(5))/2;
if(t==min(n,m)) 后手胜
else 先手胜
int Wythoff_Game(int a,int b)
{
double x=(1+sqrt(5))/2;
int n=b-a;
if(a==(int)(x*n))
return 1;
return 0;
}
4.环形博弈
n个石子围成一个环,每次取一个或者取相邻的两个,取完最后石子的人胜
if 石子数<=2 先手胜
else 先手输(消灭不对称因素后对称取石子)
5.斐波那契博弈
一堆石子n个
- 先手不能在第一次把所有的石子取完,至少取一颗
- 之后每次可以取得石子数至少为1,至多为对手取得石子数的2倍
- 约定取走最后一个石子的人为赢家
结论:若n为斐波那契数列,则后手胜
参考博客:https://blog.csdn.net/qq_40907279/article/details/83718880