#define N(negative) 必败状态
#define P(positive) 必胜状态
1:巴什博奕
假如是我们先取;
如果此时剩下1~m个石子,那我们就可以直接取完。
如果剩下大于m个呢?我们先来想:
我们取走r个后,如果给对面剩下了1~m个,那对面就可以直接取完,我们为了赢就肯定必须得留给对面大于m个,这样才能让对面取不完,那不妨就留给对面m+1个,刚好对面怎么取,剩下的个数都在1~m之间,那我们就可以直接取完;
那么根据递归的思想,我们要经过多次操作后,回到留给对面m+1个石子的状态;如果能这样取,那我们就必定能赢,否则对面就会把m+1个石子状态留给我们;
假如现在有n个;(n>>m)那么我们也就要取一个数然后剩下k*(m+1)个石子给对面,之后的话,假如对面取a个石子,那么我们取b个,使得a+b=m+1;经过多次操作后我们最终就可以将m+1个石子状态留给对面;
ok,现在有n个石子,所以我们要判断n%(m+1)是否等于0?如果不等于0,也就是说我们可以取一些石子然后剩下k*(m+1)个石子,这样的话那我们就必胜;如果等于0,那对方就可以重复我们的操作,让我们必败;
所以总结下来就是判断:n%(m+1)==0是否成立。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
if(n%(m+1)!=0){
cout<<"first"<<endl;
}else {
cout<<"second"<<endl;
}
}
2:威佐夫博弈
我们用( a [ k ] , b [ k ] ) 表示两堆物品的数量并称其为局势,显然(0,0)为必输局势,这种必输局势我们称为奇异局势。
前几个奇异局势是:(0,0),(1,2),(3,5),(4,7),(6,10),(8,13),(9,15),(11,18),(12,20)
a[k]为前k-1中的a[i]b[i]中未出现的最小非负整数 , b[k]=a[k]+k (a[0]=b[0]=0)
公式 :
a [ k ] = [ k ( 1 + √ 5 ) / 2 ] , b [ k ] = a [ k ] + k ;
威佐夫博弈这种题就背板子,唉;
对于先取的人,如果小的那一堆能写成上面的公式,那就输,否则赢,
int main(){
int a,b;
while(scanf("%d%d",&a,&b)!=EOF){
if(a>b)swap(a,b);
int k=b-a;
int ans=(a!=floor(k*(1.0+sqrt(5.0))/2));
if(ans==1){
printf("WIN");
}else {
printf("LOSE");
}
return 0;
}
3:尼姆博弈
用到异或运算;
如果我们要赢,那么我们最后面对的状态就必须是只有一堆还有物品,那么其他堆的东西就是被取完了,如果要实现这种状态,那我们就可以,对方取多少,我们就在任意可以取相同数目的一堆取走相同数目,这就可以使用异或运算;直接判断最后能不能到达那种状态;
#incldue<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int s[N];
int main()
{
int p,k;
int i,j;
cin>>p;
while(p--){
cin>>k;
int ans=1;
for(i=1;i<=n;i++){
cin>>s[i];
ans^=s[i];
}
if(ans==1){
printf("WIN");
}else{
printf("LOSE");
}
}
}
唉,理解老师的痛苦了,自己理解了但是恼火怎么讲给别人,让别人也理解;