1、巴什博弈

一堆石子,有n个,两个人轮流取,每次至少取1个,至多取m个,拿走最后一个石子的人获胜

假设一堆石子有  n=m+1  由于一次只能取m个,无论先手取多少个,后手总能拿走剩余的,这时一定是先手负

于是找到取胜规则:

一对石子  n=(m+1)*r+s

对于先手应该先取走s个,设后手取走k个,先手再取走  m+1-k    剩余的石子个数为  (m+1)(r-1)  以后保持这样的取法,先取者获胜

总之,就是要留给对手  m+1的倍数

可以归结为:   s=0时,后手胜

                    s<>0时,先手胜

2、简单的石子游戏

有n堆石子,每次至少取一根,至多拿走整堆,两人轮流拿,每次限拿其中一堆,取走最后一根的获胜。

1902年获胜策略已由美国数学家C.L.Bouton分析完成,用到的是二进制和平衡状态概念。其结论是:
对于n堆石子,第i (1<=i<=n)堆石子的个数是Xi,该状态为必败状态当且仅当   X1 XOR  X2 XOR……Xn=0。

看个例子:

有4堆石子,数量分别为:7   9   12   15
二进制形式为
 0111
 1001
 1100
 1111
异或结果为:1101

1101^1001=0100=4     可以从第二堆拿走5个

1101^1100=0001=1     也可以从第三堆拿走11个

1101^1111=0010=2     或者从第四堆取走13个

比如这道题:http://www.acmicpc.sdnu.edu.cn/Problem.aspx?pid=1294

给定N堆石子,两人轮流取石子,必须先取完一堆石子才能取另一堆,而且另一堆石子的个数必须比之前取的那一堆小,每次只能取1个或者质数个石子。如果没有石子可以取了,那么他就输了。问先手是否有必胜策略。

其实对于这个游戏,我们只需要判断第一堆石子即可,也就是石子数目最少的那一堆

代码:

#include<iostream> 
#include<algorithm>
#include<math.h>
using namespace std; 
int isprime(int n){
    int s=(int)sqrt(n);
    if(n==1)  return 1;
    for(int i=2;i<=s;i++){
        if(n%i==0)
            return 0;
        break;
    }
    return 1;

}
int main(){
    int n,a[100000],x,i,j,t;
    while(cin>>n){
        for( i=0;i<n;i++)
            cin>>a[i];  //每堆石子的数目
        sort(a,a+n);
            for(j=1;j<=a[0];j++){
                if(isprime(j)&&j<=a[0])
                    a[0]=a[0]-j;
                x=0;
                for(t=0;t<n;t++)
                    x^=a[t];
                if(x==0){
                    cout<<"yes"<<endl;
                    break;
                }else
                    a[0]=a[0]+j;  //恢复石子数目
            }
            if(x!=0)
                cout<<"no"<<endl;
        
    }
        return 0;
}
View Code

相关文章:

  • 2021-07-17
  • 2021-10-06
  • 2021-09-02
  • 2022-02-14
  • 2021-12-04
  • 2021-07-19
  • 2022-02-24
  • 2021-12-04
猜你喜欢
  • 2021-09-26
  • 2021-06-30
  • 2022-02-28
  • 2022-01-01
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案