bzoj千题计划307:bzoj5248: [2018多省省队联测]一双木棋(对抗搜索)
https://www.lydsy.com/JudgeOnline/problem.php?id=5248
先手希望先手得分减后手得分最大,后手希望先手得分减后手得分最小
棋盘的局面一定是阶梯状,且从上往下递减
可以将轮廓线作为状态,记忆化搜索
用n个数表示一个状态,第i个数表示第i行放了几个
记忆的状态表示当棋盘为这个状态时,接下来再下的最有解
记忆化搜索节省的是接下来再下的时间
#include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 11 using namespace std; int n,m; int a[N][N],b[N][N]; struct node { int v[N]; node() { memset(v,0,sizeof(v)); } bool operator < (node p) const { for(int i=1;i<=n;++i) if(v[i]<p.v[i]) return true; else if(v[i]>p.v[i]) return false; } }; map<node,int>mp; int dfs(node now,bool who) { if(mp.find(now)!=mp.end()) return mp[now]; int i; for(i=1;i<=n;++i) if(now.v[i]<m) break; if(i>n) return 0; int s; if(!who) s=-2e9; else s=2e9; for( i=1;i<=n;++i) if(now.v[i]!=m && (now.v[i]<now.v[i-1] || i==1)) { now.v[i]++; if(!who) s=max(s,dfs(now,who^1)+a[i][now.v[i]]); else s=min(s,dfs(now,who^1)-b[i][now.v[i]]); now.v[i]--; } return mp[now]=s; } int main() { // freopen("data.in","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",&a[i][j]); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",&b[i][j]); node now; printf("%d",dfs(now,0)); }