九省联考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); }