[博弈] 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值