九省联考2018 D1T1 一双木棋

Alice和Bob轮流在n*m的棋盘上放棋子

a[i][j]表示Alice放在这的收益,b[i][j]表示Bob放在这的收益

一个地方没有棋子且它的左边上边都有棋子才能放棋子,边界外视为有一圈棋子

n,m<=10,求两人都用最优方案时,Alice可以赢多少

sol:上次用的轮廓线dp,现在已然不会写了...真是个sb

写了上次口胡出来的方法,考虑棋子放出来的形状,显然,每行棋子小于等于上一行放的棋子

那状态也不多嘛,可以哈希出来然后对抗搜索

mask[i]表示第i行已经放了多少棋子

对抗搜索的时候,每一步更换游戏者,游戏者A要让ret尽量大,游戏者B要让ret尽量小

不卡自然溢出好评

#include<bits/stdc++.h>
#define LL unsigned long long
using namespace std;
inline LL read()
{
    LL x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
int n,m;
int a[2][15][15];
int mask[15];
map<LL,int> hsh;
const LL base = 137;
inline LL getmask()
{
    LL ans = 0;
    for(int i=1;i<=n;i++)ans = ans * base + mask[i];
    return ans;
}
inline int dfs(LL curmask,int opt)
{
    if(hsh.count(curmask))return hsh[curmask];
    int ret = opt ? 1e9 : -1e9;
    for(int i=1;i<=n;i++)
        if(mask[i] + 1 <= mask[i - 1])
        {
            mask[i]++;
            if(opt)ret = min(ret,dfs(getmask(),opt ^ 1) - a[1][i][mask[i]]);
            else ret = max(ret,dfs(getmask(),opt ^ 1) + a[0][i][mask[i]]);
            mask[i]--;
        }
    return hsh[curmask] = ret;
}
int main()
{
    n = read(),m = read();
    for(int k=0;k<=1;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                a[k][i][j] = read();
    for(int i=1;i<=n;i++)mask[i] = m;
    hsh[getmask()] = 0;memset(mask,0,sizeof(mask));
    mask[0] = m;
    cout<<dfs(getmask(),0);
}
View Code
原文地址:https://www.cnblogs.com/Kong-Ruo/p/9760029.html