首页 > 代码库 > [博弈] hdu 3683 Gomoku

[博弈] hdu 3683 Gomoku

题意:

两个人下五子棋,给你现有棋盘,判断在三步之内的胜负情况。

输出分为几种。

1、棋盘不合法

2、黑或白在第一步赢下在(x,y)点,多个输出x最小的、y最小的。

3、输在第二步

4、黑或白在第三步赢在(x,y)点,多个输出x最小的、y最小的。

5、三步内不分胜负

思路:

首先先判断棋盘是否合法

然后就是需要一个寻找当前我要下黑棋或者白棋在棋盘中我有几个必胜点。

所谓的必胜点就是我下这个位置我能连五子或者以上。

然后就是

1、一步直接赢(我有一个或以上的必胜点)

2、二步直接输(对方有两个以上的必胜点)

3、对方有且只有一个必胜点(我第一步堵上对方的必胜点,然后看我有没有2个必胜点,有我三步胜,没有三步内不分胜负)

4、枚举我可以下的每一个点,看看下完我有没有两个必胜点,有的话三步赢,没有的话三步内不分胜负。

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
int map[22][22];
int move[8][2]= {{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1}};
int n;
struct winpoint
{
    int cnt,x,y;
    winpoint()
    {
        cnt=x=y=0;
    }
};
int dfs(int x,int y,int f,int key)
{
    int xx=x,yy=y;
    int sum=0;
    while(1)
    {
        sum++;
        xx+=move[f][0];
        yy+=move[f][1];
        if(xx<0||yy<0||xx>=15||yy>=15) break;
        if(map[xx][yy]!=key) break;
    }
    return sum;
}
winpoint ok1(int key)
{
    winpoint ans;
    for(int i=0; i<15; i++)
    {
        for(int j=0; j<15; j++)
        {
            if(map[i][j]!=-1) continue;
            int f=0;
            for(int k=0; k<4; k++)
            {
                if(dfs(i,j,k,key)+dfs(i,j,k+4,key)-1>=5) f=1;
                if(f) break;
            }
            if(f)
            {
                if(ans.cnt==0)
                {
                    ans.x=i;
                    ans.y=j;
                }
                ans.cnt++;
            }
        }
    }
    return ans;
}
int main()
{
    while(scanf("%d",&n),n)
    {
        memset(map,-1,sizeof(map));
        int f=-1;
        int bl,wh;
        bl=wh=0;
        while(n--)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            map[x][y]=z;
            if(z) bl++;
            else wh++;
        }
        if(bl<wh||bl>=wh+2)   //不合法
        {
            puts("Invalid.");
            continue;
        }
        int key;
        if(bl==wh) key=1;
        else key=0;
        winpoint ans;
        ans=ok1(key);

        if(ans.cnt>=1)   //一步直接赢
        {
            printf("%s",key?"Place black ":"Place white ");
            printf("at (%d,%d) to win in 1 move.\n",ans.x,ans.y);
            continue;
        }
        ans=ok1(key^1);
        if(ans.cnt>=2)   //两个必胜点 直接输
        {
            puts("Lose in 2 moves.");
            continue;
        }
        if(ans.cnt==1)   //填对方必胜点 看能否赢
        {
            map[ans.x][ans.y]=key;
            winpoint tep=ok1(key);
            if(tep.cnt>=2) //对方堵不住 直接赢
            {
                printf("%s",key?"Place black ":"Place white ");
                printf("at (%d,%d) to win in 3 moves.\n",ans.x,ans.y);
                continue;
            }
            else   //不能则不分胜负
            {
                puts("Cannot win in 3 moves.");
                continue;
            }
        }
        for(int i=0; i<15; i++)  //枚举每个点
        {
            for(int j=0; j<15; j++)
            {
                if(map[i][j]!=-1) continue;
                map[i][j]=key;
                winpoint tep=ok1(key);
                if(tep.cnt>=2)
                {
                    printf("%s",key?"Place black ":"Place white ");
                    printf("at (%d,%d) to win in 3 moves.\n",i,j);
                    f=1;
                }
                if(f==1) break;
                map[i][j]=-1;
            }
            if(f==1) break;
        }
        if(f==-1) puts("Cannot win in 3 moves.");
    }
    return 0;
}


[博弈] hdu 3683 Gomoku