/*HDU 4315 以便自己学习以及回顾*/
一列棋子,中间空格若干。有一个棋子记为king ,双方轮流移动棋子,可以走任意步数,不能越过其他棋子,走到顶部移除。把king移到顶部的选手为胜利。
此题的简化版本是不考虑King的存在,双方一直走到不能走的一方为负。此时的解法是根据人数的奇偶性:把人从上顶向下的位置记为a1,a2,...an, 如果为偶数个人,则把a(2i-1)和a(2i)之间的距离当做一个Nim堆,变成一共n/2堆的Nim游戏;如果为奇数个人,则把山顶到a1的距离当做一个Nim堆,a(i*2)到a(i*2+1)的距离当做Nim堆,一共(n+1)/2堆。
考虑King的情况和上述版本几乎一致,只要把King当作普通人一样处理即可。
除了两种特殊情况:1. 当King是第一个人时,Alice直接胜 2. 当King是第二个人且一共有奇数个人时,第一堆的大小需要减1。
核心:
模型转化,从最后面的开始,两个棋子构成一个nim石子堆,将复杂的棋盘问题分解成nim问题。在各自空间内,相互独立开来。
证明过程:
不存在king的情况下,把棋子的移动转化为nim博弈的操作过程,结果等效。若存在的king,当king不为第一个时,情况其实是等效的,只是在局部操作的时候,可以通过最后步的操作来,在游戏过程中,从nim博弈的必胜态,直接把king移到顶部,来获胜。
关键是特殊情况2。把第一堆的个数减一,就是为了防止,在过程中将king移到顶部。即,过程中king最多移到第一个,而不能到达顶部。当nim博弈结束时,即所有的棋子紧挨了,即把每一堆都取完了。而这个时候,面对P态的选手,只能移动第一个棋子到顶部,,这个时候,另一个选手取胜。
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<cmath>
#include<algorithm>
using namespace std;
int n,k;
int f[1010];
int mark;
int main()
{
int i;
while(scanf("%d%d",&n,&k)!=EOF)
{
mark=0;
for(i=0;i<n;i++)
scanf("%d",&f[i]);
if(k==1){printf("Alice\n");continue;}
if(n%2==1)
{
if(k==2) mark=f[0]-1;
else mark=f[0];
for(i=1;i<n;i=i+2)
{
mark^=(f[i+1]-f[i]-1);
}
}
else
{
for(i=0;i<n;i+=2)
{
mark^=(f[i+1]-f[i]-1);
}
}
if(mark==0) printf("Bob\n");
else printf("Alice\n");
}
return 0;