zoukankan      html  css  js  c++  java
  • P4363 [九省联考2018]一双木棋chess

    传送门

    很神奇的一题

    看一眼题目感觉是博弈论?

    但是要求具体结果

    好像搞不了...

    发现题目有限制,保证棋子排列呈阶梯型

    好像可以轮廓线DP?

    不会....

    然后去看题解了,DFS能过???

    emmm....

    因为棋子排列呈阶梯型,所以如果我们暴力枚举所有的状态可以发现合法状态只有不到40万种

    然后就可以直接上min-max对抗搜索了(不懂min-max对抗搜索的请百度

    但是搜索也有一些技巧,有很多重复的状态

    所以我们可以把每种状态压缩一波,然后把答案放到map里,如果这个状态之前找过了,就直接用就好了

    为了知道当前是取min还是max,所以还要把状态解压,判断一下

    具体实现还是看代码吧

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<map>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=17,base=11,INF=1e9+7;
    
    int n,m;
    int A[N][N],B[N][N];
    int c[N];//c存当前状态
    inline ll hsh()//把当前状态压缩并返回压缩后的值
    {
        ll res=0;
        for(int i=1;i<=n;i++) res=res*base+c[i];
        return res;
    }
    inline void unzip(ll x) { for(int i=n;i;i--) c[i]=x%base,x/=base; }//把状态解压
    inline bool pd()//判断当前是谁走
    {
        int res=0;
        for(int i=1;i<=n;i++) res+=c[i];
        return res&1;//返回1说明是后手,0说明是先手
    }
    map <ll,int> mp;//存状态
    int dfs(ll sta)
    {
        if(mp.find(sta)!=mp.end()) return mp[sta];//如果走过就直接返回之前求的值
        unzip(sta); bool flag=pd();//解压状态并判断谁走
        int res= flag ? INF : -INF;//后手取min,先手取max
        for(int i=1;i<=n;i++)//枚举每一行
        {
            if(c[i]>=c[i-1]) continue;//判断当前行是否能落子
            c[i]++; ll nex=hsh();//求出下一状态
            if(flag) res=min(res,dfs(nex)-B[i][c[i]]);
            else res=max(res,dfs(nex)+A[i][c[i]]);
            c[i]--;//回溯
        }
        mp[sta]=res;//存一下当前状态的结果
        return res;
    }
    int main()
    {
        n=read(); m=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) A[i][j]=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) B[i][j]=read();
    
        for(int i=1;i<=n;i++) c[i]=m; ll las=hsh();//把结束状态存一下
        mp[las]=0;/*结束状态值为0*/ c[0]=m;//第1行可以不考虑上一行
        dfs(0);
        printf("%d",mp[0]);
        return 0;
    }
  • 相关阅读:
    不同操作系统的宏定义区分
    WINDOWS下VS编译opencv并加载自定义模块
    基于模板匹配的马赛克检验
    [转]C++模板详解
    [Linux命令]Unix/Linux信号量的使用
    [C/C++基础]读写文件
    [Linux命令]查看Linux系统相关命令
    【Linux命令】查找命令
    【QT相关】文件、目录基础操作
    【MFC相关】图片显示
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9800210.html
Copyright © 2011-2022 走看看