图论中的最小生成树基础解析

笔记哥 / 04-23 / 47点赞 / 0评论 / 199阅读
## 简介 首先给出生成子图的定义(From OI Wiki): ![image](https://cdn.res.knowhub.vip/c/2504/23/16c5b69a.png?G1cAAMTsdJxIfCK026hD2jvFHc2ARRpBpYT1es9Z%2byb6fgdD4zNan74%2f%2fKb16STQAlMCI7MiBDBYAJPKIVXLpV7ZNK7h) 嗯……有点抽象,不妨简化一下: 有一个图 \(G\),如果删去 \(G\) 中的若干条边与若干个点得到一个图 \(G'\),且图 \(G'\) 还保证连通,则称 \(G'\) 为 \(G\) 的生成子图。 那么显然,如果 \(G'\) 是一棵树,那么 \(G'\) 称为 \(G\) 的生成树。 显然,生成树不一定唯一。 那么,最小生成树的“最小”决定于你要求什么,是点权或是边权?由你自己决定。 ## 分析 这是一张较为经典的图: ![image](https://cdn.res.knowhub.vip/c/2504/23/a3ca820a.png?G1cAAMTW3Dgp8AJZ22gDdWfqnTUDFmkElRLW6%2fn%2ftS%2bi9wswNN%2bj9Rn7w29an0EFesCVwDBWpACGsLO4eZJajU8rkLxGAA%3d%3d) 那么这方案求最小生成树: - 使用 dfs 递归选或不选,再判断是否联通 但是 dfs 递归时间本来就慢,而判连通则需更多的时间复杂度,显然不可行。 但是,我们可以~~当和珅~~贪心! > > 1. 按照边权排序 > 2. 选择边7-4,连通7,4 > 3. 选择边2-8,连通2,8 > 4. 选择边1-0,连通1,0 > 5. 选择边0-5,连通0,5 > 6. 选择边1-8,连通1,8 > 7. 选择边1-6,连通1-6 > 8. 选择边3-7,连通3,7 > 9. 选择边6-5,但是由于6,5已经连通,所以可以不加此边 > 10. 选择边1-2,但是由于1,2已经连通,所以可以不加此边 > 11. 选择边6-7,连通6,7 > 12. 已经形成一棵树,后面的边都不选了 那么我们发现,这个方法需要两种操作: - 判断两个点是否在同一连通块内 - 将两个点添加到同一个连通块内 于是,基于并查集与贪心实现的Kruskal闪亮登场!!! ## 实现 ### [Luogu P3366【模板】最小生成树](https://www.luogu.com.cn/problem/P3366) 首先,定义结构体数组Edge{u,v,w}来表示一条边,使用fa数组来表示并查集 输入及初始化:![image](https://cdn.res.knowhub.vip/c/2504/23/74d44d9e.png?G1cAAER17rxgW1dF%2fU48pgkCCTYDFmkElRLW6%2fn%2fuS6R9wsomO9e24j14Te1jRAHC3YKFJsSKUBhbiAdyXBYOenQPHsA) 并查集基本操作:![image](https://cdn.res.knowhub.vip/c/2504/23/e0532191.png?G1UAAMTsdJxIfBK026hD2jvFHc2ARBZBpYT1es9Z%2byb6fgdD4zNan74%2f%2fKX16STQgqwEhrEiaDCSAMXYwgXJqQriGg4%3d) kruskal操作: 特殊处理: 可以发现,在最后如果图本身不连通,还需输出 `orz` ,我们可以发现,如果图本身不连通,那么最后就不会是一棵树,即 \(n-1\not=m\),判断即可。 ![image](https://cdn.res.knowhub.vip/c/2504/23/975402c7.png?G1cAAER17rxgW1fQ%2bJ14TBMEEmwGLNIIKiWs1%2fP%2fa18i7xdQMN%2bj9Rn7w29anyEOHqgUKIoSKcBhpqWyMplDYacTeY0A) ### [Luogu P2820 局域网](https://www.luogu.com.cn/problem/P2820) 读题后可以发现,依旧是求最小生成树,只需在一开始求出边权总和,在最后求差值即可。 主要代码:![image](https://cdn.res.knowhub.vip/c/2504/23/d5217325.png?G1YAAMTsdJxI8gmq26hD2jvFHc2ARBZBpYT1es9Z%2byb6fgfD4jNan74%2f%2fKX16aSwgmwERmJD8FAIoLWoBpOcWa5qcQ0H)