Life Winner Bo
题目链接
题目大意
给你一个棋盘,要求从左上角走到右下角,最先走到右下角的人赢,规定只能朝右下方走(右,下或者右下),现在有4种国际象棋的棋子,如果按照它们在国际象棋内的规则走棋的话,现在B先手,双方足够聪明,问谁最后能赢得比赛。
题解
四种棋子分别是:
- King
- Castle
- Knight
- Queen
对于Queen来讲,是经典的威佐夫博弈问题,我们可以直接求解,对于其它几种棋子,我们一个一个来分析。
- Castle
Castle的移动比较简单:向右,或者向下移动任意格,我们不难发现,如果我们一开始就保证和终点在一条对角线上,一定是先手赢,所以必胜策略就是先手移动到对角线上——然而如果一开始就是一个正方形,那先手肯定必败了。
- King
King的移动跟Castle有点像:向右,向下,或者向右下移动一格。看上去没有Castle那么好分析,其实不然,我们从终点开始分析,我们画出离终点2步远的必败点,发现只有3个,且组成了一个边长为3的正方形,在这个正方形内,其余的点全是必胜点,因为只需要一步就可以移动到必败点。这样我们发现,我们如果以某个必败点作为终点,我们又可以扩展出一个同样的正方形,这样循环往复,我们可以画出棋盘上所有必败点。最终结论:n-1和m-1均为偶数是必败点,否则我可以先手达到一个必败的状态使得对手先手必败。
- Knight
Knight的移动方法跟马一样走日字,它比较难处理,因为它有和局的情况(比如某个人一直往右走,导致对面无路可走)这样的方法确实猥琐,但是也确实使对手无法获得胜利…这样的情况看似麻烦,其实我们也可以用相同的思想分析必胜和必败状态。
我们先区分能分出胜负的局面和平局的局面,通过画图,我们可以发现(2,3)和(3,2)这样的情况是一定先手必胜的,而想(3,3)这种情况就无法达到,更进一步,我们发现(4,4)这种情况是一定必败的,而其他比它小的情况全部是平局。
更进一步,我们发现(5,6)这种情况也是必胜的:我们只需要先手走到(2,3)这个点就可以——等等,这里我们好像发现了什么:在之前,我们知道(4,4)是先手必败,而在这里,我们如果把(2,3)看作起始点,把(5,6)看作终点,其组成的正方形和刚才那种情况一模一样:这说明这就是一种可以区分胜负的局面,从(4,4)开始,(7,7),(10,10)….均为先手必败,然而我们如果可以先手走到这样一种必败的局面,我们即是必胜的——而其余情况,全为和局。
到这里我们就可以写出最终结果了:当终点减去起点的坐标能被3整除的时候,先手必败;对于必胜条件,我们只需要判断(2,3)和(3,2)是否可以达到必败局面就可以了。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const double c=(1+sqrt(5))/2;
int T,t,n,m;
int g[1005][1005];
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&t,&n,&m);
if (t==1)
{
if ((n-1)%2==0 && (m-1)%2==0) printf("G\n");
else printf("B\n");
continue ;
}
if (t==2)
{
if (n==m) printf("G\n");
else printf("B\n");
}
if (t==3)
{
if (n==m && n%3==1) printf("G\n");
else if (n-2==m-1 && (n-2)%3==1) printf("B\n");
else if (n-1==m-2 && (n-1)%3==1) printf("B\n");
else printf("D\n");
}
if (t==4)
{
n--; m--;
if (n>m) swap(n,m);
int k=m-n,a,b;
a=k*c; b=a+k;
if (a==n && b==m) printf("G\n");
else printf("B\n");
}
}
return 0;
}