斯坦纳树
Dijkstra+堆貌似慢了一倍
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,lim=1,F[12][12][1050],a[12][12],vis[12][12],instack[12][12];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
struct node{
int x,y,sta;
}Pre[12][12][1050],q[1000005];
void spfa(int now){
// printf("ans:%d
",now);
int head=0,tail=1;
memset(instack,0,sizeof(instack));
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++){
q[++tail]=(node){i,j,0};
instack[i][j]=1;
}
while (head<tail){
head++;
int x=q[head].x,y=q[head].y;
instack[x][y]=0;
for (int i=0; i<4; i++){
int fx=x+dx[i],fy=y+dy[i];
if (fx<1 || fx>n || fy<1 || fy>m) continue;
if (F[fx][fy][now]>F[x][y][now]+a[fx][fy]){
F[fx][fy][now]=F[x][y][now]+a[fx][fy];
Pre[fx][fy][now]=(node){x,y,now};
if (!instack[fx][fy]){
instack[fx][fy]=1;
q[++tail]=(node){fx,fy,0};
}
}
}
}
}
void solve(int x,int y,int now){
if (!now) return;
int X=Pre[x][y][now].x,Y=Pre[x][y][now].y,sta=Pre[x][y][now].sta;
solve(X,Y,sta);
if (X==x && Y==y){
if (sta) solve(X,Y,now-sta);
}
else vis[x][y]=1;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++){
scanf("%d",&a[i][j]);
if (a[i][j]==0) lim<<=1;
}
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
for (int now=1; now<lim; now++)
F[i][j][now]=1e9;
int num=0;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
if (!a[i][j]) {
F[i][j][1<<num]=0;
num++;
}
for (int now=1; now<lim; now++){
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
for (int sta=now; sta; sta=((sta-1)&now)){
if (F[i][j][now]>F[i][j][sta]+F[i][j][now-sta]-a[i][j]){
F[i][j][now]=F[i][j][sta]+F[i][j][now-sta]-a[i][j];
Pre[i][j][now]=(node){i,j,sta};
}
}
spfa(now);
}
int ansx=0,ansy=0;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
if (!a[i][j]){
ansx=i,ansy=j;
break;
}
solve(ansx,ansy,lim-1);
printf("%d
",F[ansx][ansy][lim-1]);
for (int i=1; i<=n; i++){
for (int j=1; j<=m; j++)
if (!a[i][j]) printf("x");
else if (vis[i][j]) printf("o");
else printf("_");
printf("
");
}
return 0;
}