【斯坦纳树】【模板】

题目

使关键点联通的最小边权

题解

一般关键点很少,用状压
f i , s < = M i n ( f i , t + f i , s − t ) f i , s < = M i n ( f j , s + v a l j , i ) f_{i,s}<=Min(f_{i,t}+f_{i,s-t})\\ f_{i,s}<=Min(f_{j,s}+val_{j,i}) fi,s<=Min(fi,t+fi,st)fi,s<=Min(fj,s+valj,i)
前者状压DP,后者最短路DP
最后统计答案,然后就水了一篇板子

#include<bits/stdc++.h>
using namespace std;
const int N=1e2+10,M=1e3+10,S=1<<10,INF=0x3F3F3F3F;
int n,m,k,id[N];
int head[N],nex[M],to[M],val[M],tot;
void build(int u,int v,int w){tot++;nex[tot]=head[u];to[tot]=v;val[tot]=w;head[u]=tot;}
int f[N][S];
priority_queue<pair<int,int> >q;
bool vis[N];
void dj(int s)
{
	memset(vis,0,sizeof(vis));
	while(!q.empty())
	{
		int u=q.top().second;q.pop();
		if(vis[u])continue;vis[u]=1;
		for(int i=head[u];i;i=nex[i])
		{
			int v=to[i];
			if(f[v][s]>f[u][s]+val[i])
			{
				f[v][s]=f[u][s]+val[i];
				q.push(make_pair(-f[v][s],v));
			}
		}
	}
}
int main()
{
	memset(f,0x3F,sizeof(f));
	scanf("%d%d%d",&n,&m,&k);
	for(int x,y,z,i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		build(x,y,z);build(y,x,z);
	}
	for(int i=1;i<=k;i++)scanf("%d",&id[i]),f[id[i]][1<<(i-1)]=0;
	for(int s=1;s<(1<<k);s++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int t=(s-1)&s;t;t=(t-1)&s)
				f[i][s]=min(f[i][s],f[i][t]+f[i][s^t]);
			if(f[i][s]<INF)q.push(make_pair(-f[i][s],i));
		}
		dj(s);
	}
	int ans=INF;
	for(int i=1;i<=n;i++)ans=min(ans,f[i][(1<<k)-1]);
	printf("%d",ans);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值