分析
显然,合法的状态数不会太多。
于是可以状压一下轮廓线 (其实就是记录一下每行填到了哪一列) ,然后写一发对抗搜索。
然后如果用 $\mathrm{map}$ 记状态的话可能会T,于是用 $\mathrm{unordered\_map}$ 就行了。
具体实现及细节见代码。
代码
//It is made by M_sea
#include <unordered_map>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define re register
typedef long long ll;
using namespace std;
inline int read() {
int X=0,w=1; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
return X*w;
}
const int N=10+10;
const int BASE=12;
int n,m;
int a[N][N],b[N][N],h[N];
unordered_map<ll,int> f;
inline ll encode() {
ll ans=0;
for (re int i=1;i<=n;++i) ans=ans*BASE+h[i];
return ans;
}
inline void decode(ll s) {
for (re int i=n;i;--i) h[i]=s%BASE,s/=BASE;
}
inline int calc() { //根据已经下的棋子的奇偶性,判断谁下这一步
int s=0;
for (re int i=1;i<=n;++i) s+=h[i];
return s&1;
}
inline int dfs(ll sta) {
if (f.find(sta)!=f.end()) return f[sta]; //记忆化
decode(sta); int op=calc(),ans=op?1e9:-1e9;
for (re int i=1;i<=n;++i) {
if (h[i-1]<=h[i]) continue;
++h[i];
if (op) ans=min(ans,dfs(encode())-b[i][h[i]]);
else ans=max(ans,dfs(encode())+a[i][h[i]]);
--h[i];
}
return f[sta]=ans;
}
int main() {
n=read(),m=read(); h[0]=m;
// 这里 h[0]=m 是为了搜索时更方便判断
for (re int i=1;i<=n;++i)
for (re int j=1;j<=m;++j)
a[i][j]=read();
for (re int i=1;i<=n;++i)
for (re int j=1;j<=m;++j)
b[i][j]=read();
for (re int i=1;i<=n;++i) h[i]=m; f[encode()]=0; //这里处理一下终态
printf("%d\n",dfs(0));
return 0;
}