版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88821900
洛谷传送门
BZOJ传送门
解析:
很裸的斯坦纳树,细节也不是很多,注意拼凑的时候要减去根节点的重复贡献。
为了输出方案,只需要记录一下 转移的方向就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
re bool f=0;
while(!isdigit(c=gc()))f^=c=='-';re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
}
using namespace IO;
using std::cout;
using std::swap;
cs int N=20;
int n,m,p,ex,ey;
cs int INF=1e9;
int f[1<<11][N][N];
int val[N][N];
struct Pre{
int x,y,s;
Pre(){}
Pre(cs int &_x,cs int &_y,cs int &_s):x(_x),y(_y),s(_s){}
}pre[1<<11][N][N];
struct Pos{int x,y;Pos(cs int &_x,cs int &_y):x(_x),y(_y){}};
cs int dx[4]={0,1,0,-1};
cs int dy[4]={1,0,-1,0};
std::queue<Pos,std::list<Pos> > q;
bool in[N][N];
inline void SPFA(int S){
while(!q.empty()){
int x=q.front().x,y=q.front().y;q.pop();
in[x][y]=false;
for(int re i=0;i<4;++i){
int nx=x+dx[i],ny=y+dy[i];
if(nx<1||nx>n||ny<1||ny>m)continue;
if(f[S][nx][ny]>f[S][x][y]+val[nx][ny]){
f[S][nx][ny]=f[S][x][y]+val[nx][ny];
if(!in[nx][ny])q.push(Pos(nx,ny)),in[nx][ny]=true;
pre[S][nx][ny]=Pre(x,y,S);
}
}
}
}
bool set[N][N];
void dfs(int x,int y,int S){
if(!pre[S][x][y].s)return ;
set[x][y]=true;
Pre &p=pre[S][x][y];
dfs(p.x,p.y,p.s);
if(p.x==x&&p.y==y)dfs(x,y,S^p.s);
}
signed main(){
memset(f,0x3f,sizeof f);
n=getint(),m=getint();
for(int re i=1;i<=n;++i)
for(int re j=1;j<=m;++j){
val[i][j]=getint();
if(!val[i][j]){
f[1<<p][i][j]=0;++p;
ex=i,ey=j;
}
}
for(int re s=1;s<(1<<p);++s){
for(int re i=1;i<=n;++i)
for(int re j=1;j<=m;++j){
for(int re k=s&(s-1);k;k=s&(k-1))
if(f[s][i][j]>f[k][i][j]+f[s^k][i][j]-val[i][j]){
f[s][i][j]=f[k][i][j]+f[s^k][i][j]-val[i][j];
pre[s][i][j]=Pre(i,j,k);
}
if(f[s][i][j]<INF)q.push(Pos(i,j)),in[i][j]=true;
}
SPFA(s);
}
std::ios::sync_with_stdio(false);
cout<<f[(1<<p)-1][ex][ey]<<"\n";
dfs(ex,ey,(1<<p)-1);
for(int re i=1;i<=n;++i,cout<<"\n")
for(int re j=1;j<=m;++j)
if(!val[i][j])cout<<"x";
else if(set[i][j])cout<<"o";
else cout<<"_";
return 0;
}