建议做这道题目之前先看一下--------->>>点击打开链接
题意:
有 n 个球分别在 n 个不同的位置,Alice 和 Bob 依次选择一个球向上移动,上面有球不能越过,谁最后把红球移出谁就赢!
博弈问题,先考虑如果总数n为偶数(k!=1),当n个点全两两挨在一起时,谁先走谁输
举个例子如果
n==4 k==3 那么 先手怎么走你怎么走即可,你只需要把第2堆棋子在要进入山顶的时候把他放在靠近山顶一步的位置。那么相当于这一步给了对方,剩下的还是对方走什么你走什么就可以。对两两之间的配对异或就行。
n==4 k==4这样的话两两配对,对方走第一个你走第二个就可以。对两两之间的配对异或就行。
当总数n为奇数时(k!=1),先吧第一个点走道终点,然后就是偶数的情况了,然后考虑怎么将他们两两挨在一起(注意不用所有点都挨在一起)
这是就是当n为偶(k!=1)计算a[i+1]与a[i]的距离,for(i+=2),这样我们就将它化成几点nim游戏问题,将a[i+1]与a[i]的距离左为每堆石子的个数
当n为奇数,就是a自己当作一个堆,然后还是将a[i+1]与a[i]的距离左为每堆石子的个数,轮到谁没有石子取了,谁就输啦!当然注意特殊情况就是当n为奇数的时候,k如果为2,前面我们说当n为奇数是直接将第一个直接走到终点,但因为第二哥是k了,所以第一个a[i]不能走道终点,只能走道里终点最近的位置也就是只能走a[i]-1步,所以就是将a[i]-1当作一个堆。
考虑了好长时间为什么k对整个游戏无影响,其实在第一个的时候就模拟了。这个问题解决了。再来考虑n的奇偶问题,这里有个特殊的例子,就是当n为奇数k==2.看了别人的博客没看懂,后个人认为为什么要考虑这个地方呢,主要是因为当k==1的时候肯定先手赢所以当k==2时,第一堆是不能全走完的否则后手就赢定了。。。也可以不减去一个直接进行全部异或就行但是要特判一下。
真的好神奇,,,看了好长时间才勉强接受。。。。
#include<iostream>
#include<cstring>
#include<cstdio>
#define MAXN 1010
using namespace std;
int a[MAXN];
int main()
{
int n,k,i;
while(cin>>n>>k)
{
memset(a,0,sizeof(a));
for(i=1;i<=n;i++) scanf("%d",&a[i]);
if(k==1)
{
cout<<"Alice"<<endl;
continue;
}
int t;
if(n%2==0)
{
t=a[2]-a[1]-1;
for(i=4;i<=n;i=i+2) t=t^(a[i]-a[i-1]-1);
if(t==0)cout<<"Bob"<<endl;
else cout<<"Alice"<<endl;
}
else
{
t=a[1];
if(k==2) t-=1;
for(i=3;i<=n;i=i+2) t=t^(a[i]-a[i-1]-1);
if(t==0)cout<<"Bob"<<endl;
else cout<<"Alice"<<endl;
}
}
return 0;
}
这个是对特殊情况特判了一下
#include<iostream>
#include<cstring>
#include<cstdio>
#define MAXN 1010
using namespace std;
int a[MAXN];
int main()
{
int n,k,i;
while(cin>>n>>k)
{
memset(a,0,sizeof(a));
for(i=1; i<=n; i++) scanf("%d",&a[i]);
if(k==1)
{
cout<<"Alice"<<endl;
continue;
}
int t;
if(n%2==0)
{
t=a[2]-a[1]-1;
for(i=4; i<=n; i=i+2) t=t^(a[i]-a[i-1]-1);
if(t==0)cout<<"Bob"<<endl;
else cout<<"Alice"<<endl;
}
else
{
t=a[1];
for(i=3; i<=n; i=i+2) t=t^(a[i]-a[i-1]-1);
if(k==2)
{
if(t==0) cout<<"Alice"<<endl;
else cout<<"Bob"<<endl;
}
else
{
if(t==0)cout<<"Bob"<<endl;
else cout<<"Alice"<<endl;
}
}
}
return 0;
}