【HDU】5754 Life Winner Bo

来源:互联网 发布:js filereader 编辑:程序博客网 时间:2024/05/18 02:20

Life Winner Bo


题目链接

  • 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;}
0 0
原创粉丝点击