bzoj1457 棋盘游戏

题目描述:

$100*100$的棋盘上有$n$个$Queen$,每个$Queen$可以向左,向下,向左下移动。

两人轮流操作,将任何一个$Queen$移动到$(0,0)$的人获胜。

一个位置上可以有很多$Queen$,$Queen$移动时不需要考虑经过路径上是否有$Queen$。

题解:

这个很像$Nim$游戏,不过这个游戏是移动一个到$(0,0)$即可。

两个人都不是傻子,所以有其他选择之前都不会给对方送棋。

所以我们可以猜到起手不能到$(0,0)$的情况下,一定会有所有$Queen$聚集在$(1,2)$和$(2,1)$的壮观场面。

两步之后,游戏结束。

所以有棋子可以直接到$(0,0)$时,先手获胜;

其他情况下,将最后一个$Queen$移动到$(1,2)$或$(2,1)$的人获胜。

这两个点相当于终止节点。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 105;
int T,n,sg[N][N];
int dfs(int x,int y)
{
    if(~sg[x][y])return sg[x][y];
    if((x==1&&y==2)||(x==2&&y==1))return sg[x][y]=0;
    bool tmp[10*N]={0};
    for(int i=1;i<x;i++)if(x-i!=y)tmp[dfs(x-i,y)]=1;
    for(int i=1;i<y;i++)if(y-i!=x)tmp[dfs(x,y-i)]=1;
    for(int i=1;i<x&&i<y;i++)tmp[dfs(x-i,y-i)]=1;
    for(int i=0;;i++)if(!tmp[i])return sg[x][y]=i;
}
int main()
{
    scanf("%d",&T);
    memset(sg,-1,sizeof(sg));
    while(T--)
    {
        scanf("%d",&n);
        int ans = 0;
        bool ot = 0;
        for(int x,y,i=1;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            if(x&&y&&x!=y)ans^=dfs(x,y);
            else ot=1;
        }
        if(ot)puts("^o^");
        else puts(ans?"^o^":"T_T");
    }
    return 0;
}

 

posted @ 2019-01-22 23:06  LiGuanlin  阅读(152)  评论(0编辑  收藏  举报