SCU 3133(博弈)

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

题意:在一张由 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个骑士,在同一时间可有多个骑士在同一格子,谁不能移动谁输现在给定初始棋面,问先手是否有必胜的策略?

分析:假设全部的子游戏都为败态,那么先者必输

        如果其中有某些为胜态,那么先者可以将所有的胜态都转为败态,最终先者必胜

这里说一下博弈的重要思想:假设N状态为必胜态,P状态为必败态,则

所有的终止状态都是P状态;

对于任何的N状态,肯定存在一种方式可以一步转到一个P状态;

对于任何的P状态,不管怎么走步,都只能转到N状态。

因此这题(0,0),(0,1),(1,0),(1,1)肯定是必败态,所有可以到达这4点的格子肯定为必胜态,而所有只能到达必胜态的格子肯定为必败态,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));
        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);
            if(sg[x][y])flag=1;
        }
        if(flag)puts("yes");
        else puts("no");
    }
}
View Code
原文地址:https://www.cnblogs.com/lienus/p/4326416.html