分析:
斯坦纳树
第一次写,非常费劲
因为每个寺庙只需找到一口井,也就是寺庙的位置到井的位置只需一条路,所以我们的最后的最优解一定得到的是一棵树
但是朴素的斯坦纳树是没有点权的,我们可以增加一个0点来连接所有的点,其边权就是挖井的花费
按上面的思路套个斯坦纳树模版
ans=min(cost[i][(1<<(n+1))−1])(i<=i<=n+m)
a
n
s
=
m
i
n
(
c
o
s
t
[
i
]
[
(
1
<<
(
n
+
1
)
)
−
1
]
)
(
i
<=
i
<=
n
+
m
)
tip
说实话我也不是很明白这种算法。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
const int M=1010;
const int N=10010;
struct node{
int y,nxt,v;
};
node way[N];
int st[M],tot=0,n,m,p;
int f[M][100],bit[M],dp[100];
bool in[M][100];
queue<int> Q;
void add(int u,int w,int z)
{
tot++;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}
void spfa()
{
while (!Q.empty())
{
int now=Q.front(); Q.pop();
int x=now&1023,stx=now>>10;
in[x][stx]=0;
for (int i=st[x];i;i=way[i].nxt)
{
int y=way[i].y,sty=stx|bit[y];
if (f[x][stx]+way[i].v<f[y][sty])
{
f[y][sty]=f[x][stx]+way[i].v;
if (stx==sty&&!in[y][sty])
{
Q.push((sty<<10)|y);
in[y][sty]=1;
}
}
}
}
}
void solve()
{
int nn=1<<n+1;
while (!Q.empty()) Q.pop();
memset(in,0,sizeof(in));
for (int i=0;i<nn;i++)
{
for (int j=1;j<=n+m;j++)
{
for (int k=(i-1)&i;k;k=(k-1)&i)
f[j][i]=min(f[j][i],f[j][k|bit[j]]+f[j][(i-k)|bit[j]]);
if (f[j][i]<INF)
{
Q.push((i<<10)|j);
in[j][i]=1;
}
}
spfa();
}
memset(dp,0x3f,sizeof(dp));
for (int i=0;i<nn;i++)
for (int j=1;j<=n+m;j++)
dp[i]=min(dp[i],f[j][i]);
for (int i=0;i<nn;i++)
if (i&(1<<n))
{
for (int j=(i-1)&i;j;j=(j-1)&i)
if (j&(1<<n))
dp[i]=min(dp[i],dp[j]+dp[(i-j)|(1<<n)]);
}
printf("%d\n",dp[nn-1]);
}
int main()
{
while (scanf("%d%d%d",&n,&m,&p)!=EOF)
{
memset(st,0,sizeof(st)); tot=0;
memset(f,0x3f,sizeof(f));
memset(bit,0,sizeof(bit));
for (int i=1;i<=n+m;i++)
{
int x;
scanf("%d",&x);
if (i<=n){
bit[i]=1<<i-1;
f[i][bit[i]]=0;
f[i][bit[i]|(1<<n)]=x;
}
else f[i][1<<n]=x;
}
for (int i=1;i<=p;i++)
{
int u,w,z;
scanf("%d%d%d",&u,&w,&z);
add(u,w,z); add(w,u,z);
}
solve();
}
return 0;
}