bzoj1457 棋盘游戏

9 篇文章 0 订阅

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值