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; }