斯坦纳树是一棵连接给定点集的树,其中边不一定在这些点里面连。
可以使用 dp,设
\(f_{i,S}\)
表示 钦定
\(i\)
为根,连接了集合
\(S\)
的最小代价,转移分两种情况:
\(i\)
度数为
\(1\)
,可以转移到和它相连的点
\(j\)
;
\(i\)
度数不为
\(1\)
,可以由子集转移。
第一种转移用最短路求即可。
const int N=110,M=510;
int n,m,k,ss[N];
struct Edge {
int to,nxt,w;
}e[M<<1];
int hd[N],cnt;
il void ade(int u,int v,int w){
e[++cnt].to=v,e[cnt].w=w,e[cnt].nxt=hd[u],hd[u]=cnt;
int f[N][2000];bool vis[N];
queue<int> q;
void SPFA(int S){
memset(vis,0,sizeof vis);
for(rg int i=1;i<=n;i++){
if(f[i][S]!=INF)q.push(i),vis[i]=1;
while(!q.empty()){
int u=q.front();q.pop(),vis[u]=0;
for(rg int i=hd[u];i;i=e[i].nxt){
int v=e[i].to;
if(f[v][S]>f[u][S]+e[i].w){
f[v][S]=f[u][S]+e[i].w;
if(!vis[v])q.push(v),vis[v]=1;
int main(){
Read(n),Read(m),Read(k);
for(rg int i=1,u,v,w;i<=m;i++){
Read(u),Read(v),Read(w),ade(u,v,w),ade(v,u,w);
memset(f,0x3f,sizeof f);
for(rg int i=1;i<=k;i++){
Read(ss[i]);
f[ss[i]][1<<i-1]=0;
for(rg int S=0;S<(1<<k);S++){
for(rg int i=1;i<=n;i++){
for(rg int T=S&(S-1);T;T=S&(T-1)){
f[i][S]=min(f[i][S],f[i][T]+f[i][S^T]);
SPFA(S);
cout<<f[ss[1]][(1<<k)-1]<<endl;
KafuuChino HotoKokoa