SCU 3132(博弈)

 

传送门:windy和水星 -- 水星游戏 1 

题意:在一张由 n*m 的格子组成的棋盘上放着 k 个骑士每个骑士的位置为(xi,yi),表示第xi行,第yi列骑士如果当前位置为(x,y),一步可以走的位置为

(x-2,y-1)

(x-2,y+1)

(x-1,y-2)

(x+1,y-2)

两人对弈,每次移动一个骑士,在同一时间可有多个骑士在同一格子,谁不能移动谁输现在给定初始棋面,问先手是否有必胜的策略?

分析:将k个骑士当成k个子游戏,然后求出k个子游戏的sg值,然后问题转换成有k堆石子,每堆有sg[i]个石子,先手可以选择一堆取1~sg[i]个石子,取完最后的石子的人赢,这就变成裸Nim游戏,将所有sg值异或判断是否为0即可。

#include <cstdio>

#include <cstring>

#include <algorithm>

#define N 110

using namespace std;

int n,m,k;

int sg[N][N];

int dx[]={-2,-2,-1,1};

int dy[]={-1,1,-2,-2};

bool judge(int a,int b)

{

    return a>=0&&a<n&&b>=0&&b<m;

}

int dfs(int x,int y)

{

    if(~sg[x][y])return sg[x][y];

    int vis[5],temp;

    memset(vis,false,sizeof(vis));

    for(int i=0;i<4;i++)

    {

        int a=x+dx[i],b=y+dy[i];

        if(!judge(a,b))continue;

        if((temp=sg[x][y])==-1)temp=dfs(a,b);

        vis[temp]=1;

    }

    for(int i=0;i<5;i++)

    {

        if(vis[i])continue;

        return sg[x][y]=i;

    }

}

int main()

{

    while(scanf("%d%d%d",&n,&m,&k)>0)

    {

        memset(sg,-1,sizeof(sg));

        sg[0][0]=sg[0][1]=sg[1][0]=sg[1][1]=0;

        for(int i=0;i<n;i++)

            for(int j=0;j<m;j++)

            if(sg[i][j]==-1)dfs(i,j);

        int x,y,flag=0;

        while(k--)

        {

            scanf("%d%d",&x,&y);

            flag^=sg[x][y];

        }

        if(flag)puts("yes");

        else puts("no");

    }

}
View Code

 

你可能感兴趣的:(sc)