最小斯坦纳树

什么鬼名字,不如叫做扩展最小生成树。

定义

规范定义像是专门不让人看懂来提高算法高级度的,这里说一说比较易懂的定义。

先想最小生成树,它问的是使图上所有点联通的最小边权和。那么如果把所有点改为指定点,并允许其他点存在,那么这就是所谓的最小斯坦纳树。

求法

模板题

它的求法和最小生成树没有半毛钱关系,反而要用到最短路。

考虑 dp ,根据题目数据范围容易想到状压 dp,设 dpmask,i 表示以 i 节点为当前斯坦纳树的根,应选择的点的状态为 mask 时的最小代价。

初值先全部赋成极大值,对于每个特殊点让每个对应的状态变成 0

转移的时候分两种情况,首先考虑不换根的情况,正常状压,方程如下:

dpmask,i=minsmask(dps,i+dpmaskx,i)

枚举所有子集转移。子集枚举是小技巧。

考虑换根的情况,方程为:

dpmask,i=min(dpmask,j+vi,j)

转移的时候用最短路转移。

Code

点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=998244353;
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
inline ll read_()
{
	ll w=1;ll s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10ll+(ch-'0');ch=getchar();}
	return w*s;
}
const int maxn=1e5+10;
int n,m,k;
ll ans=1e18;
struct no
{
	int y,v;
};
struct dij
{
	int y;
	ll d;
	inline friend bool operator < (dij x,dij y)
	{
		return x.d>y.d;
	}
};
priority_queue<dij> q;
bool vis[maxn];
vector<no> G[maxn];
int c[maxn];
ll dp[35][maxn];
void dijkstra(int s)
{
	for(int i=0;i<=n;i++)vis[i]=0;
	while(!q.empty())
	{
		int u=q.top().y;
		q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(auto i : G[u])
		{
			int y=i.y;ll v=i.v;
			if(dp[s][y]>dp[s][u]+v)
			{
				dp[s][y]=dp[s][u]+v;
				q.push({y,dp[s][y]});
			}
//			cout<<dp[s][y]<<' ';
		}
//		cout<<endl;
	}
}
signed main()
{
	cin>>n>>k>>m;
	for(int i=0;i<=n;i++)
	{
		for(int mask=0;mask<=(1<<k);mask++)
		{
			dp[mask][i]=1e18;
		}
	}
	for(int i=1;i<=k;i++)
	{
		int x=read();
		dp[1<<(i-1)][x]=0;
	}
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read();ll v=read_();
		G[x].push_back({y,v});
		G[y].push_back({x,v});
	}
	for(int mask=1;mask<(1<<k);mask++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=mask&(mask-1);j;j=(j-1)&mask)
			{
				dp[mask][i]=min(dp[mask][i],dp[j][i]+dp[mask^j][i]);
			}
			if(dp[mask][i]<dp[0][0])
			{
				q.push({i,dp[mask][i]});
			}
		}
		dijkstra(mask);
//		for(int j=1;j<=n;j++)
//		{
//			cout<<dp[j][mask]<<' ';;
//		}cout<<endl;
	}
	for(int i=1;i<=n;i++)ans=min(ans,dp[(1<<k)-1][i]);
	cout<<ans;
	return 0;
}
posted @   Redamancy_Lydic  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示