最小斯坦纳树

发布时间:2022-07-05 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了最小斯坦纳树脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

题意:

给出一张 (n) 个点的无向图,其中 (k) 个点是关键点,问可以将所有关键点相连的最小网络是多大。

Solution:

考虑 DP ,(f_{i,S}) 表示做到 (i) 号点,包含关键点的集合为 (S) ,考虑转移有两种方式:

  1. (f_{i,S|T} = f_{i,S} + f_{i,T})
  2. (f_{x,S} = f_{y,S} + w(y,x))

第一个枚举子集,第二个 spfa 或 dij 转移。

#include<bITs/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int N=110;
const int M=1010;
const int SZ=1e5;
const int LIM=1030;
const int INF=1e9+7;
int n,m,k,tot,last[N],f[N][LIM],ans;
bool bz[N];
int st,en;
int q[SZ+5];
struct Edge{
	int st,en,v,next;
}E[M];
void add(int x,int y,int z){
	E[++tot]=(edge){x,y,z,last[x]};
	last[x]=tot;
}
void spfa(int S){
	st=en=0;
	fo(i,1,n)
		if(f[i][S]<f[0][0])q[++en]=i,bz[i]=1;
	while(st!=en){
		int x=q[++st];
		for(int p=last[x];p;p=E[p].next){
			int y=E[p].en;
			if(f[y][S]>f[x][S] + E[p].v){
				f[y][S]=f[x][S] + E[p].v;
				if(!bz[y]){
					q[++en]=y;
					bz[y]=1;
				}
			}
		}
		bz[x]=0;
	}
}
int main(){
	freoPEn("data.in","r",stdin);
	freopen("data.out","w",stdout);
	scanf("%d%d%d",&amp;n,&;m,&k);
	fo(i,1,m){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	memset(f,127,sizeof(f));
	fo(i,1,k){
		int x;
		scanf("%d",&x);
		f[x][1<<i-1]=0;
	}
	fo(i,1,n)f[i][0]=0;
	int lim=(1<<k)-1;
	fo(S,1,lim){
		fo(i,1,n){
			for(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);
	}
	ans=INF;
	fo(i,1,n)ans=min(ans ,f[i][lim]);
	PRintf("%dn",ans);

	return 0;
}

脚本宝典总结

以上是脚本宝典为你收集整理的最小斯坦纳树全部内容,希望文章能够帮你解决最小斯坦纳树所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。