斯坦纳树。
(f[i][j][s]) 表示当前 ((i,j)) 覆盖关键点的状态为 (s) 的最小代价。
(f[i][j][s]=min(f[i][j][s],f[i][j][s { m xor} t]+f[i][j][t]-a[i][j]))
(f[i+{ m dx}][j+{ m dy}][s]=min(f[i+{ m dx}][j+{ m dy}][s],f[i][j][s]+a[i+{ m dx}][j+{ m dy}]))
第一个式子直接DP;第二个式子在第一个式子DP完后跑一边spfa即可。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=20,Inf=0x3f3f3f3f,dx[]={0,-1,0,1},dy[]={1,0,-1,0};
int n,m,tot,sx,sy;
int a[N][N],f[N][N][1<<11];
bool vis[N][N],ans[N][N];
struct node {int x,y,s;}lst[N][N][1<<11];
struct pt {int x,y;};
queue<pt> q;
inline void spfa(int s) {
while(q.size()) {
R x=q.front().x,y=q.front().y; q.pop();
vis[x][y]=false;
for(R i=0;i<4;++i) {
R xx=x+dx[i],yy=y+dy[i];
if(xx<1||xx>n||yy<1||yy>m) continue;
if(f[x][y][s]+a[xx][yy]<f[xx][yy][s]) {
f[xx][yy][s]=f[x][y][s]+a[xx][yy];
if(!vis[xx][yy])
q.push((pt){xx,yy}),vis[xx][yy]=true;
lst[xx][yy][s]=(node){x,y,s};
}
}
}
}
inline void dfs(int x,int y,int s) {
if(!lst[x][y][s].s) return ;
ans[x][y]=1;
R i=lst[x][y][s].x,j=lst[x][y][s].y,t=lst[x][y][s].s;
dfs(i,j,t);
if(i==x&&j==y) dfs(i,j,s^t);
}
inline void main() {
n=g(),m=g(),tot=0;
memset(f,0x3f,sizeof f);
for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) {
a[i][j]=g();
if(!a[i][j]) sx=i,sy=j,f[i][j][1<<tot]=0,++tot;
}
for(R s=1,lim=1<<tot;s<lim;++s) {
while(q.size()) q.pop();
for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) {
for(R t=s;t;t=s&(t-1))
if(f[i][j][s]>f[i][j][t]+f[i][j][s^t]-a[i][j]) {
f[i][j][s]=f[i][j][t]+f[i][j][s^t]-a[i][j];
lst[i][j][s]=(node){i,j,t};
}
if(f[i][j][s]!=Inf)
q.push((pt){i,j}),vis[i][j]=true;
}
spfa(s);
}
printf("%d
",f[sx][sy][(1<<tot)-1]);
dfs(sx,sy,(1<<tot)-1);
for(R i=1;i<=n;++i,putchar(10)) for(R j=1;j<=m;++j) {
if(!a[i][j]) {putchar('x'); continue;}
putchar(ans[i][j]?'o':'_');
}
}
} signed main() {Luitaryi::main(); return 0;}
2020.01.18