HDU5754 Life Winner Bo

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5754


【题意】B和G,在一个N*M的棋盘上下棋,棋子初始位置再(1,1),目标是走到(n,m)。棋子移动的位置必须是在其右下方向,及移动后的位置(x',y')相对原位置(x,y),x'≥x,y'≥y,同时棋子不能超出棋盘界限。有4种棋子,国王,马,车,皇后。棋子的移动规则同国际象棋,及国王可以向四周8个格子移动一格,题中可以向右下3个格子移动;马可以走日字,题中可以向右下两个位置移动;车可以直线无限格移动,题中可以向下和右移动无限格;皇后可以直线和斜线无限格移动,题中可以向下,右,右下三个方向无限格移动。每次给定棋子类型和棋盘大小,两人轮流移动棋子,谁先将棋子移动至(n,m)谁赢,棋子无法移动至(n,m)为平局。


【分析】由于每次只进行一个游戏,采用sg值的思想,区别为必败态标记0,必胜态标记1,平局标记-1。预处理出1000*1000棋盘四种棋子的所有解。国王:利用&操作判断三个后继是否存在0,存在则该格子是必胜态填1,否则为必败态填0;马:由于马存在平局的可能,判断马的两个后继是否存在0,存在则该格子为必胜态填1,否则判断是否存在-1,存在该格子为平局态填-1,都为1则该格子为必败态填0;车:简单找一下规律可以发现只有行列相等的时候是必败态填0,其他均为必胜态填1;皇后:比赛时通过打表找到的规律,由于对称,以i<j举例。以(0,0)为终点的话,下面的点是(1,2),(3,5),(4,7)。规律每次i=i+1,若i的数之前未出现过,j=j+2,该格子为必败态填0;若i出现过,j=j+1,不进行处理继续循环。比赛结束被告知皇后就是是威佐夫博弈=.=||,具体是什么不知道可以百度一下。循环结束后所有非0的格子均为必胜态填1。


【代码】

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
int sg[1010][1010][5];
vector<int> v[5];
int kx[3]={0,-1,-1},ky[3]={-1,0,-1};
int nx[2]={-1,-2},ny[2]={-2,-1};
int re[1010];
void init(){
    memset(sg,-1,sizeof(sg));
    for(int i=1;i<=4;++i)
        sg[0][0][i]=0;
    int tmp=0;
    for(int i=1;i<=1000 && tmp<=1000;++i){
        if(re[i]){
            tmp++;
            continue;
        }
        tmp+=2;
        re[i]=re[tmp]=1;
        sg[i][tmp][4]=sg[tmp][i][4]=0;
    }
    for(int i=0;i<=1000;++i)
        for(int j=0;j<=1000;++j){
            if(i==0 && j==0)
                continue;
            int tmp=1;
            for(int k=0;k<3;++k)
                if(i+kx[k]>=0 && j+ky[k]>=0 && sg[i+kx[k]][j+ky[k]][1]!=-1)
                    tmp&=sg[i+kx[k]][j+ky[k]][1];
            sg[i][j][1]=(!tmp);
            if(i==j)
                sg[i][j][2]=0;
            else
                sg[i][j][2]=1;
            tmp=1;
            int fla=0,fla2=0;
            for(int k=0;k<2;++k)
                if(i+nx[k]>=0 && j+ny[k]>=0){
                    if(sg[i+nx[k]][j+ny[k]][3]!=-1){
                        tmp&=sg[i+nx[k]][j+ny[k]][3];
                        fla=1;
                    }
                    else
                        fla2=1;
                }
            if(fla){
                if(tmp){
                    if(fla2)
                        sg[i][j][3]=-1;
                    else
                        sg[i][j][3]=0;
                }
                else
                    sg[i][j][3]=1;
            }
            if(sg[i][j][4]!=0)
                sg[i][j][4]=1;
        }
}
int main(){
    init();
    int T,t,n,m;
    cin>>T;
    while(T--){
        scanf("%d %d %d",&t,&n,&m);
        n--;
        m--;
        if(sg[n][m][t]==1){
            cout<<"B\n";
            continue;
        }
        if(sg[n][m][t]==0){
            cout<<"G\n";
            continue;
        }
        cout<<"D\n";
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值