hunnu 10884(简单博弈论,记忆化搜索)

题目链接:点击打开链接

此人输了的条件是无论怎么走:对方都赢了

此人获胜的条件是有至少一种方式可以获胜,那么能获胜
此人平手的条件是至少有一种方式平手

状态压缩+记忆化深搜

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#define Alice 0
#define Bob 1
#define Win 0
#define Lose 1
#define Draw 2
using namespace std;
const int N=10;
const int repeat=3;
const int SIZE=4;
const int MAXN=45000000;
int dp[MAXN];
const char color[]= {'X','O'};
char chess[N][N];
//相对于下面的isVic()来说,这个判断相对过慢
/*inline bool check(int x,int y,int dx,int dy,char sn)
{
    for(int i=0;i<repeat;i++)
    {
        int cx=x+i*dx;
        int cy=y+i*dy;
        if(cx<0||cy<0||cx>=SIZE||cy>=SIZE) return false;
        if(chess[cx][cy]!=sn) return false;
    }
    return true;
}
inline bool isVic(char sn)
{
    for(int i=0;i<SIZE;i++)
        for(int j=0;j<SIZE;j++)
            if(chess[i][j]==sn)
            {
                if(check(i,j,1,1,sn)) return true;
                if(check(i,j,1,0,sn)) return true;
                if(check(i,j,0,1,sn)) return true;
                if(check(i,j,1,-1,sn)) return true;
            }
    return false;
}*/
int isVic(char ch)
{
    int i,j;
    for(i=0; i<=1; i++)
        for(j=0; j<=1; j++)
        {
            if ( ch == chess[i][j] )
            {
                if ( ch == chess[i][j+1] && ch == chess[i][j+2] )
                    return true;
                if ( ch == chess[i+1][j+1] && ch == chess[i+2][j+2] )
                    return true;
                if ( ch == chess[i+1][j] && ch == chess[i+2][j] )
                    return true;
            }
        }
    for(i=0; i<=1; i++)
        for(j=2; j<=3; j++)
            if ( ch == chess[i][j] )
            {
                if ( ch == chess[i+1][j] && ch == chess[i+2][j] )
                    return true;
                if ( ch == chess[i+1][j-1] && ch == chess[i+2][j-2] )
                    return true;
            }
    for(i=2; i<=3; i++)
        for(j=0; j<=1; j++)
            if ( ch == chess[i][j] )
                if ( ch == chess[i][j+1] && ch == chess[i][j+2] )
                    return true;
    return false;
}
const int col[]= {1,3,9,27,
                  81,243,729,2187,
                  6561,19683,59049,177147,
                  531441,1594323,4782969,14348907
                 };
inline int to_status()
{
    int ret=0;
    for(int i=0; i<SIZE; i++)
        for(int j=0; j<SIZE; j++)
        {
            int sign;
            int pos=i*SIZE+j;
            if(chess[i][j]=='_') sign=0;
            else if(chess[i][j]=='O') sign=col[pos];
            else sign=col[pos]<<1;
            ret+=sign;
        }
    return ret;
}
//返回的是该人胜负情况
//depth表示当前要下的是第depth步
int dfs(int depth,int person)
{
    if(depth==17) return Draw;
    int status=to_status();
    if(dp[status]) return dp[status];
    bool candraw=false;
    for(int i=0; i<SIZE; i++)
        for(int j=0; j<SIZE; j++)
            if(chess[i][j]=='_')
            {
                //表示落子当前点
                chess[i][j]=color[person];
                if(isVic(color[person]))
                {
                    chess[i][j]='_';
                    return dp[status]=Win;
                }
                int flag=dfs(depth+1,person^1);
                chess[i][j]='_';
                if(flag==Draw) candraw=true;
                if(flag==Lose) return dp[status]=Win;
                else continue;
                //此人输了的条件是无论怎么走:对方都赢了
                //此人获胜的条件是有一种方式可以获胜,那么能获胜
                //此人平手的条件是至少有一种方式平手
            }
    return dp[status]=candraw?Draw:Lose;
}
int main()
{
    while(scanf("%s",chess[0])!=EOF)
    {
        for(int i=1; i<SIZE; i++)
            scanf("%s",chess[i]);
        int a=0,b=0;
        for(int i=0; i<SIZE; i++)
            for(int j=0; j<SIZE; j++)
                if(chess[i][j]=='X') a++;
                else if(chess[i][j]=='O') b++;
        int sign;
        if(a==b) sign=dfs(a+b+1,Alice);
        else sign=dfs(a+b+1,Bob);
        if(sign==Win) puts("Win");
        else if(sign==Lose) puts("Lose");
        else puts("Draw");
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值