题意
题解
斯坦纳树的裸题啊。。
直接做就可以了
比较恶心的是要记录路径
输出路径的时候
如果是子集合并的情况
则需要把两个子集遍历,才可以得到正确答案
CODE:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef pair<int,int> PI;
const int N=15;
int n,m;
int f[N][N][1<<N];
struct qq
{
int x,y,sta;
}g[N][N][1<<N];
int a[N][N];
int k1=0;
queue<PI> q;
int X[4]={-1,0,0,1};
int Y[4]={0,-1,1,0};
void SPFA (int sta)
{
for (int u=1;u<=n;u++)
for (int i=1;i<=m;i++)
q.push(make_pair(u,i));
while (!q.empty())
{
int x=q.front().first,y=q.front().second;q.pop();
for (int u=0;u<4;u++)
{
int xx=x+X[u],yy=y+Y[u];
if (xx<=0||xx>n||yy<=0||yy>m) continue;
if (f[xx][yy][sta]>f[x][y][sta]+a[xx][yy])
{
f[xx][yy][sta]=f[x][y][sta]+a[xx][yy];
g[xx][yy][sta]=qq{x,y,sta};
q.push(make_pair(xx,yy));
}
}
}
}
bool vis[N][N];
void dfs (int x,int y,int sta)
{
vis[x][y]=true;
if (g[x][y][sta].x==-1) return ;
int xx=g[x][y][sta].x,yy=g[x][y][sta].y;
dfs(xx,yy,g[x][y][sta].sta);
if (xx==x&&yy==y) dfs(xx,yy,sta-g[x][y][sta].sta);
}
int main()
{
memset(vis,false,sizeof(vis));
memset(f,63,sizeof(f));
scanf("%d%d",&n,&m);
for (int u=1;u<=n;u++)
for (int i=1;i<=m;i++)
{
scanf("%d",&a[u][i]);
if (a[u][i]==0)
{
f[u][i][1<<k1]=0;
k1++;
}
}
for (int u=1;u<(1<<k1);u++)
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
g[i][j][u].x=-1;
for (int u=1;u<(1<<k1);u++)
{
for (int k=u;k!=0;k=u&(k-1))
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int t=f[i][j][k]+f[i][j][u-k]-a[i][j];
if (t<f[i][j][u])
{
f[i][j][u]=t;
g[i][j][u]=qq{i,j,k};
}
}
SPFA(u);
}
int ans=(1<<30),x,y;
for (int u=1;u<=n;u++)
for (int i=1;i<=m;i++)
if (f[u][i][(1<<k1)-1]<ans)
{
x=u;y=i;
ans=f[u][i][(1<<k1)-1];
}
memset(vis,false,sizeof(vis));
dfs(x,y,(1<<k1)-1);
printf("%d\n",ans);
for (int u=1;u<=n;u++)
{
for (int i=1;i<=m;i++)
{
if (a[u][i]==0) printf("x");
else if (vis[u][i]) printf("o");
else printf("_");
}
printf("\n");
}
return 0;
}