出题人讲这题的时候扯到了模拟退火,遗传算法,alphabeta剪枝等等
然而这题一个记忆化搜索就能跑过去
#include <iostream>
#include <cstdio>
#define INF (1<<30)
#define N 22
using namespace std;
int n,m,tp,e[N][N],map[N][N],v[N][N];
int vis[2][1<<N];
const int fx[] = {0,1,0,-1};
const int fy[] = {1,0,-1,0};
inline void ut(int &x,int y) { x = max(x,y); }
inline void check(int x,int y,int &c) {
if (map[x][y] && map[x+1][y] && map[x][y+1] && map[x+1][y+1]) c+=v[x][y];
}
int dfs(int x,int mask){
if (mask == tp) return 0;
if (vis[x][mask]) return vis[x][mask];
int ret = -INF;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) if (!map[i][j]){
map[i][j] = 1;
int val = 0;
check(i-1,j-1,val); check(i-1,j,val);
check(i,j-1,val); check(i,j,val);
if (val)
val += dfs(x,mask+e[i][j]);
else
val -= dfs(x^1,mask+e[i][j]);
ut(ret,val);
map[i][j] = 0;
}
vis[x][mask] = ret;
return ret;
}
int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
e[i][j] = 1<<( (i-1)*m+j-1 );
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) {
scanf("%d",&map[i][j]);
if (!map[i][j]) tp += e[i][j];
}
for (int i=1;i<=n-1;i++)
for (int j=1;j<=m-1;j++) scanf("%d",&v[i][j]);
//1先手 0后手
int ans = dfs(1,0);
printf("%d\n",ans);
return 0;
}