首页 > 其他分享 >最小斯坦纳树 学习笔记

最小斯坦纳树 学习笔记

时间:2024-09-04 21:24:45浏览次数:4  
标签:int 复杂度 最小 笔记 斯坦纳 转移 关键点

最小斯坦纳树

给定一张无相连通图,每条边有权值,有 \(k\) 个关键点,要求选择权值和最小的边使得关键点连通,求权值和。

类似最小生成树,但是限定了关键点就只能用指数级的复杂度解决,这里考虑类似状压 DP 的方法。

例题:P6192 【模板】最小斯坦纳树

首先最终答案显然是一个树。

所以我们设 \(f_{i,S}\) 表示以 \(i\) 为根的树,包含了关键点中 \(S\) 的这些点,\(S\) 是一个 \(01\) 串。

考虑怎么转移,分 \(i\) 的度数为 \(1\),和不为 \(1\) 两种情况。

为 \(1\) 则:

\[f_{i,S}+w(i,j)\rightarrow f_{j,S} \]

不为 \(1\) 则 \(i\) 有两个子树,把两个子树合并即可:

\[f_{i,S}+f_{i,T}\rightarrow f_{i,S+T} \]

要注意在这里我们不用关心 \(i,j\) 是否是关键点而更新后面的 \(S\),我们只需在最开始把关键点 \(i\) 赋为 \(f_{i,\{i\}}=0\) 即可,然后后面的转移相当于把这些关键点合并。

由于 \(S\) 肯定是逐渐变大的,所以考虑在最外层枚举 \(S\),用之前的状态更新当前的状态,这里是 \(O(2^k)\)。

考虑怎么实现,对于上面一条转移,注意我们不是只做一条边,可能是很多条边连起来,那么就做最短路,用优先队列 \(Dijkstra\) 可以做到 \(O(n\log m)\),具体地就是一开始把所有点都推进队列里,总的就是 \(O(2^k n\log m)\)。

对于下面这条转移,就是一个枚举子集,而枚举子集可以做到 \(3^k\),具体来说是这样(\(j\) 是 \(i\) 的子集):

for(int i=0;i<(1<<k);i++)
	for(int j=i;j;j=((j-1)&i))
        do something

所以这一部分的总复杂度是 \(O(3^k n)\)。

注意一件事情,我们需要先做度数不为 \(1\) 的转移,再做为 \(1\) 的转移,相当于是先得到更大的 \(S\),然后才能把这个 \(S\) 扩展到更多的点;否则若更大的 \(S\) 还没合并,不是最优的,那么先扩展到更多的点也不是最优的。

最后的复杂度就是 \(O(3^kn+2^k n\log m)\)。

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] 管道连接

P3638 [APIO2013] 机器人

标签:int,复杂度,最小,笔记,斯坦纳,转移,关键点
From: https://www.cnblogs.com/dccy/p/18397370

相关文章

  • 笔记-Neovim快速入门
    本文是neovim中的练习项目Tutor的笔记。建议自己手动尝试一下这个项目,很快就能上手neovim。想要尝试这个项目,只要输入:Tutor<Enter>即可。安装&启动使用包管理器apt安装即可。运行:$sudoaptinstallneovimTutorLesson1移动光标使用hjkl键可以移动光标,方向如下所......
  • PPPoE配置学习笔记
    企业内网和运营商网络如上图所示,中间交换机模拟运营商传输设备。公网IP段:12.1.1.0/24。内网IP段:192.168.1.0/24。PPPoE拨号采用CHAP认证,用户名:admin密码:admin@123实验要求:将R1设置为PPPoE客户端,R2为PPPoE服务器端;R1作为内网用户的网关,内网用户自动获取IP地址;R1上的拨号接......
  • A-LLMRec论文阅读笔记
    LargeLanguageModelsmeetCollaborativeFiltering:AnEfficientAll-roundLLM-basedRecommenderSystem论文阅读笔记Abstract现存的问题:​ 最近的策略侧重于利用基于预训练模态编码器和大型语言模型(LLM)的用户/项目模态信息(如文本或图像)。尽管它们在冷场景下非常有效,但我......
  • C语言学习笔记 Day16(文件管理--下)
    Day16 内容梳理:C语言学习笔记Day14(文件管理--上)-CSDN博客C语言学习笔记Day15(文件管理--中)-CSDN博客目录Chapter10 文件操作10.5文件状态10.6文件的随机读写fseek()、rewind()(1)fseek():移动光标并开始读写(2)rewind():将光标重置回文件开头10.7文件的删除remove(......
  • RH442 - 性能调优学习笔记(十一)
    Linux跟踪工具常用选项:-c统计数量  -e后面跟系统调用名称,列出打开的文件在遇到执行命令卡顿时,strace可以帮助排查在哪个步骤出了问题。......
  • 【自学笔记】处理类别数据、独热编码和降维(主成分分析)
    类别数据  与数值特征不同,类别数据往往更难被计算机理解,主要分为序数和标称。  序数具有顺序,比如衣服尺码中有XL>L>M等  标称不含任何顺序,特征之间相互独立。处理序数特征  为了让算法正确解读序数特征,我们需要用整数来表示。我们可以定义映射关系,训练后再反向......
  • 软件测试学习笔记丨Pytest+Allure测试计算器
    本文转自测试人社区,原文链接:https://ceshiren.com/t/topic/31954二、项目要求2.1项目简介计算器是一个经典的编程场景,可以获取两个数据的计算结果。2.1.1知识点Pytest测试框架基本用法2.1.2受众初级测试工程师2.1.3作业内容使用Pytest编写自动化测试用例对相加函数进行测试......
  • 给自己复盘的随想录笔记-字符串练习题
    反转字符串344.反转字符串-力扣(LeetCode)双指针+元素交换 classSolution{publicvoidreverseString(char[]s){chartemp;intl=0,r=s.length-1;while(l<r){temp=s[l];s[l]=s[r];s[r]=temp;l++;......
  • Python全网最全基础课程笔记(三)——所有运算符+运算符优先级
    本专栏系列为Pythong基础系列,每天都会更新新的内容,搜罗全网资源以及自己在学习和工作过程中的一些总结,可以说是非常详细和全面。以至于为什么要写的这么详细:自己也是学过Python的,很多新手只是简单的过一篇语法,其实对于一个知识点的底层逻辑和其他使用方法以及参数详情根本......
  • Python全网最全基础课程笔记(二)——变量
      本专栏系列为Pythong基础系列,每天都会更新新的内容,搜罗全网资源以及自己在学习和工作过程中的一些总结,可以说是非常详细和全面。以至于为什么要写的这么详细:自己也是学过Python的,很多新手只是简单的过一篇语法,其实对于一个知识点的底层逻辑和其他使用方法以及参数详情......