最小斯坦纳树 学习笔记
最小斯坦纳树
给定一张无相连通图,每条边有权值,有
类似最小生成树,但是限定了关键点就只能用指数级的复杂度解决,这里考虑类似状压 DP 的方法。
首先最终答案显然是一个树。
所以我们设
考虑怎么转移,分
为
不为
要注意在这里我们不用关心
由于
考虑怎么实现,对于上面一条转移,注意我们不是只做一条边,可能是很多条边连起来,那么就做最短路,用优先队列
对于下面这条转移,就是一个枚举子集,而枚举子集可以做到
for(int i=0;i<(1<<k);i++) for(int j=i;j;j=((j-1)&i)) do something
所以这一部分的总复杂度是
注意一件事情,我们需要先做度数不为
最后的复杂度就是
AC 代码:
#include<bits/stdc++.h> using namespace std; int n,m,K; const int N=105,M=505; vector<pair<int,int>> g[N]; int f[N][1<<10],bz[N]; struct arr{ int val,num; arr(int _val,int _num){ val=_val,num=_num; } }; int operator<(arr x,arr y){ return x.val>y.val; } int id[N]; int main(){ // freopen("P.in","r",stdin); ios::sync_with_stdio(0); cin>>n>>m>>K; for(int i=1;i<=m;i++){ int u,v,w; cin>>u>>v>>w; g[u].push_back(make_pair(v,w)); g[v].push_back(make_pair(u,w)); } int X; memset(f,0x3f,sizeof f); for(int i=1;i<=K;i++){ int x; cin>>x; X=x; id[x]=i; f[x][1<<i-1]=0; } for(int i=1;i<(1<<K);i++){ for(int j=i;j;j=((j-1)&i)){ for(int k=1;k<=n;k++) f[k][i]=min(f[k][i],f[k][j]+f[k][i-j]); } memset(bz,0,sizeof bz); priority_queue<arr> q; for(int k=1;k<=n;k++)q.push(arr(f[k][i],k)); while(q.size()){ int u; while(q.size()&&bz[u=q.top().num])q.pop(); if(q.empty())break; bz[u]=1; q.pop(); for(auto _v:g[u]){ int v=_v.first,co=_v.second; if(f[v][i]>f[u][i]+co){ f[v][i]=f[u][i]+co; q.push(arr(f[v][i],v)); } } } } cout<<f[X][(1<<K)-1]; }
相关练习
P4294 [WC2008] 游览计划
P3264 [JLOI2015] 管道连接
经过一些思考可以发现,最终答案一定是所有颜色所形成的斯坦纳树的并,于是对于每种颜色的斯坦纳树拿出来再做一次状压 DP 即可。
另外在这道题中,数据范围较大,因此
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】