题目:
http://acm.hdu.edu.cn/showproblem.php?pid=5754
题意:
n*m的棋盘,一枚棋子要从左上到右下,两个人轮流移动,只能向包含当前行列的左下移动,谁移动到最后一步谁胜利,有四种棋子:
1 king 向周围八个方向移动一步
2 castle 向2*3的矩阵的另一个角移动
3 knight 移动到同一行或者同一列的任意位置
4 queen 移动到同意行列斜线的任意位置
思路:
很明显是博弈论,这道题好在将四种博弈结合在了一起,棋子移动取就是两堆石子,谁先取完谁胜利,一堆石子n-1个一堆m-1个。
1:
可以在其中一堆取一个或者在两堆中各取一个,最终取到(0,0) 那就很明显了,最终结果是偶偶的,每一次偶偶都只能变成奇偶,偶奇,奇奇,然而这三种都能一次变成偶偶。于是就有答案了,谁面对偶偶的局势谁就输,对方只要保持每次都让他面对偶偶的局势就能保证取走最后的石子。这是对于n-1和m-1,对于n,m就是当n,m都为奇数时第一个人面对必败态,否则第一个人胜利。
2:
就是每次从第一堆中取1个第二堆2个,或者是第一堆2个第二堆1个,很明显当某人面对两堆数量一致并且是3的倍数时就是必败态,这样情况下他无论如何取对方都能保持让他继续面对必败态。同理某人面对必败态情况下一堆多一个一堆多两个时就是必胜态,他只需要一次性让对方面对必败态就行了。除此之外都是平局,因为都不想留给对方必胜态,所以会保持两堆的差不为1,或者不为3倍数。
3:
就是从某一堆中取出任意个,简单的nim博弈就能解决。
4:
就是每次从某一堆中取任意个或者是从两堆中取同样数量个,明显是威佐夫博弈。
代码:
//kopyh
#include <bits/stdc++.h>
using namespace std;
int n,m,sum,res,flag;
int main()
{
int i,j,k,cas,T,t,x,y,z;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&t,&n,&m);
if(t==1)
{
if((n&1)&&(m&1))printf("G\n");
else printf("B\n");
}
else if(t==2)
{
int res=0;
n--;m--;
res^=n;res^=m;
if(res==0)printf("G\n");
else printf("B\n");
}
else if(t==3)
{
n--;m--;
if(n==m&&n%3==0)printf("G\n");
else if(abs(n-m)==1&&(min(n,m)-1)%3==0)printf("B\n");
else printf("D\n");
}
else if(t==4)
{
n--;m--;
double j,k,r,R;
if(n>m)n^=m,m^=n,n^=m;
r=(sqrt(5.0)-1)/2;
R=1.0/r;
j=(int)(r*n);
if(n!=(int)(j*R))
j+=1;
printf(m!=(int)(j*R)+j?"B\n":"G\n");
}
}
return 0;
}