XJ5 基础图论算法
Kruskal 算法
Kruskal 是用来求解最大/小生成树的算法。
一棵树可以被理解为 个结点, 条边的连通图。
断开 条边,树会被分为 个连通块。
- 生成树:从一张 个点 条边的图中选出 条边,构成一棵树。
- 最小生成树:边权和最小的生成树。
- 最大生成树:边权和最大的生成树。
反向考虑一棵树的构建过程。
一开始是 个独立的联通块,每增加一条边,减少一个联通块。
直到选出 条边,构造完成。
使用并查集维护联通块。
考虑最小生成树的构造过程,即选出 条边的顺序。
有一个贪心策略,按照边权升序排序,依次考虑是否选取。
如果两个端点 在一个联通块里,不选。否则选。
- 建立并查集。
- 按照边权排序,依次扫描每条边。
- 如果 属于同一连通块,则忽略,扫描下一条。否则选择这条边,合并两个并查集。
时间复杂度为 。
例题:【模板】最小生成树
给出一个 个点, 条边的无向图,判断其是否为联通图,并求出其最小生成树。
Dijkstra 算法
Dijkstra 算法是一种用于求解单源最短路问题的算法。
设 为起点, 为 到 的最短距离。
流程如下:
- 初始化 为 , 的其他位置为 。
- 在未被标记点中找到的 最小的 ,并标记结点 。
- 扫描 的所有出边 ,如果 ,则更新 。
- 重复步骤 ,直至所有结点被标记。
Dijkstra 只能处理非负边权的图。
其思想基于贪心:当边长为非负数,全局最小值必然不可能再被更新。
即,每次在第二步中取出的 , 已经是起点到 的最短路径。
Dijkstra 的时间复杂度是 。
其时间复杂度瓶颈为寻找结点 ,这个过程可以用优先队列 priority_queue 优化。
优化后均摊时间复杂度为 。
pair <type,type>- 优先以第一关键字比大小,第一关键字相同按第二关键字比。
make_pair(a,b),得到一个以 为第一关键字, 为第二关键字的pair。
给出一个 个点 条边的有向图,求从 出发到每个点的最短距离。
为该边起点, 为该边终点, 为该边长度。
Floyd 算法
Floyd 算法是用来求解全源最短路的算法,其基于动态规划思想。
使用邻接矩阵存储图。
设 为经过若干个编号不超过 的结点从 到 的最短路长度。
有两种转移来源:
- 经过若干个编号不超过 的结点从 到 。
- 从 到 再到 。
即有 。
类似于背包问题,第一维 可以省略。
即有 。
由于动态规划的有序性,需要先枚举阶段转移点 ,再枚举 和 。
最终 即为 到 的最短距离。
Floyd 算法的时间复杂度为 。
全源最短路问题也可以通过做 次 Dijkstra 在 的时间复杂度内完成。
例题:【模板】Floyd 算法
给出一个 个点 条边的无向图,求任意两点间最短路径。