Description
有一个100 * 100的棋盘,其中左下角的编号为(0, 0), 右上角编号为(99, 99)。棋盘上有N个Queen,最开始第i个Queen的位置为(Xi, Yi)。现在有两个玩家依次来操作,每一次一个玩家可以选择其中一个Queen,将它跳到(Xi – k, Yi)或(Xi, Yi - k)或(Xi – k, Yi - k), 其中k > 0。注意在游戏的过程中,一个格子里面可能出现多个Queen。如果谁先将任意一个Queen移动到(0, 0), 谁就获胜。问先手必胜还是后手必胜?
注意本题是多组数据。 第一行有一个数T, 表示数据组数。 接下来有T组数据,每组数据的第一行一个正整数N表示Queen的个数。接下来N行每行两个数表示第i个Queen的初始位置Xi, Yi(0 <= Xi <= 99, 0 <= Yi <= 99)。
对于每一组数据,你需要输出是先手必胜还是后手必胜。 如果是先手必胜,输出“^o^“, 如果是后手必胜,输出”T_T”。
T <= 10, N <= 1000
Solution
弄懂了sg函数的含义就很好做了,这题稍微不同的是第一个移动到0,0的人赢
那么就把一步能赢的点sg标记为0,接下来就变成谁不能走谁就输的经典模型了,套一下就ok
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int N=100;
int sg[N+5][N+5];
int rec[20005],tot;
int n;
bool check(int x,int y) {
if (x==1||y==1||x==y) return 0;
return 1;
}
int get_SG(int x,int y) {
tot++;
rep(i,1,x-1) if (check(x-i,y)) rec[sg[x-i][y]]=tot;
rep(i,1,y-1) if (check(x,y-i)) rec[sg[x][y-i]]=tot;
rep(i,1,std:: min(x,y)-1) if (check(x-i,y-i)) rec[sg[x-i][y-i]]=tot;
for (int i=0;;++i) if (rec[i]!=tot) {
return i;
}
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
rep(i,1,N) rep(j,1,N) sg[i][j]=get_SG(i,j);
int T; scanf("%d",&T);
while (T--) {
scanf("%d",&n);
int sum=0; bool flag=false;
rep(i,1,n) {
int x,y; scanf("%d%d",&x,&y);
if (!check(++x,++y)) flag=true;
sum^=sg[x][y];
}
if (sum||flag) puts("^o^");
else puts("T_T");
}
return 0;
}