【图论】生成树问题合集
包括了最小生成树、次小生成树、斯坦纳树和最小树形图的模板
最小生成树
最小生成树(Minimum Spanning Tree,MST),字面意思,由连通图生成,包含所有节点,是一棵树,且边权和最小。
Kruskal
- 对边排序,从小到大如果端点不在同一集合里就加边到生成树里
- 复杂度 ,适用于稀疏图
- 证明:归纳法证明任何时候该算法选择的边集都被某棵 MST 所包含
- 基础:对于算法刚开始时,显然成立(最小生成树存在)
- 假设某时刻成立,当前边集为 ,令 为这棵 MST,考虑下一条加入的边
- 如果 则成立
- 鸽了
1 | int kruskal() |
Prim
每次取到目前集合距离最小的点加入
暴力
每次遍历所有点到当前点集的距离,找到最小的加入(标记已访问),更新它到其他点的最小距离。
复杂度
1 | bool vst[N]; |
堆优化
1 | priority_queue<pii, vector<pii>, greater<pii>> q; |
次小生成树
非严格次小生成树
- 设MST的边集为 ,剩余边集为 ,则有
- 对于 到 的路径中最长的一条边,用 替换它,得到一个权值和为 ,对所有的替换取最小值
- 其中最长的一条边用倍增lca来求就可以,板子里没用倍增
1 | const int N = 1e3 + 10, INF = 0x7fffffff; |
严格次小生成树
1 | //使用:跑MST,加边的时候调用insedge,并将一个全局used[i]函数标记为真 |
斯坦纳树
定义
给定n个点,试求连接此n个点,总长最短的直线段连接系统,并且任意两点都可由系统中的直线段组成的折线连接起来。
分析
模板题:无向连通图,可能自环和重边,给定k个关键点,求一个子图使得边权和最小。
- 子图一定是树,否则一定可以去环使得边权和变小。这棵树就是最小斯坦纳树。
- 设 表示 为根,包含点集 中所有点的最小权值和
- 设 是 的子集,则 由 转移而来。
- 松弛操作,对于 的相邻节点 :
步骤
- 将 初始化为
- 枚举给定点的子集
- 对于 枚举子集 ,更新每个节点的
- 如果权值和被更新,说明这个点可行,加入 的队列
- 进行 更新队列中点的相邻点的答案
- 答案是给定点中的任意点 的 值
代码
1 | for (int i = 0; i < k; i++) |
最小树形图
有向图的最小生成树,从根节点能到所有节点,且每条边权值和最小。
朱刘算法(Edmonds 算法), 。
模板题:给定包含n个结点,m条有向边的一个图。输出以结点r为根的最小树形图每条边的权值之和,如果没有以r为根的最小树形图,输出-1。
步骤
- 统计每个点的最小入边,加入答案
- 如果有一个点找不到入边,说明不能生成最小树形图,返回-1
- 每个点由最小入边找环缩点
- 其余点不变,重构图,边权修改为原边权-到达节点最小入边
代码
1 | int in[N], pre[N]; //in[i]记录每轮i点入边中最小的边权,pre[i]记录最小边权对应的端点编号 |
注意
- 给坐标的注意精度
- 最小生成森林,可跑并查集,连通块个数tot,则最大生成森林的边数为n-tot
- 给出一些已知边,跑MST时将这些边权值取0的处理方法