图论四大算法(Prim、Kruskal、Dijkstra、Floyd)总结
最小生成树问题
Prim 算法
从某一个结点开始构建生成树,每次将代价最小的新结点纳入生成树,直到所有的结点都纳入为止。
算法实现
1 | for (int k = 0; k < n - 1; k++) // 算法总共需要 n - 1 轮处理 |
Kruskal 算法
每次选择一条权值最小的边,使这条边的两头连通,直到所有的结点都连通为止。
总结
Prim 算法和 Kruskal 算法的核心思想都是贪心原则,但区别在于前者从顶点(结点)出发构建生成树,后者从边出发构建生成树。
最短路径问题
解决最短路径问题可以使用最基本的 BFS 算法,但它只适用于在无权图上,求单源最短路径的情况,这是远远不够的。
Dijkstra 算法
适用于在带正权图(包括无权图,即每条边的权值为 1)上,求单源最短路径。从某一个结点开始寻找到其他所有结点的最短路径,每次选择代价最小的新结点,并更新最短路径数组,直到所有可达的结点都选择完毕。
算法实现
1 | for (int k = 0; k < n - 1; k++) // 算法总共需要 n - 1 轮处理 |
总结
Prim 算法和 Dijkstra 算法虽然高度相似,但除了目的不同(前者用于构建最小生成树,后者用于求最短路径)、适用范围不同(前者适用于无向图,后者适用于有向图)之外,最大的区别在于前者更新的是已标记集合到未标记结点之间的距离,后者更新的是源点到未标记结点之间的距离,即所谓的「代价最小」说的不是一回事。
Bellman-Ford 算法
适用于在带权图(包括正权图、负全图和无权图)上,求单源最短路径。每次都考察图中所有的边,不断更新最短路径数组,直到最短路径数组不再更新为止。
1 | for (int k = 0; k < n - 1; k++) // 算法总共需要 n - 1 轮处理 |
Floyd - Warshall 算法
适用于在带权图(包括正权图、负全图和无权图)上,求多源最短路径,可以求出每一对顶点(结点)之间的最短路径。
算法描述
从第一个结点开始考察作为中转点的情况,寻找所有结点对之间的最短路径,每次新增一个可允许中转的结点,并更新最短路径矩阵,直到所有结点都被考察完毕。
设最短路径矩阵为 $\pmb{D}$,当前考察的中转点为 $k$,则 Floyd 算法的状态转移方程为
但由于
同理有
因此可以忽略 $k$,状态转移方程变形为
算法实现
1 | for (int k = 0; k < n; k++) // 考虑以第 k 个结点作为中转点 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 埃苯泽の小窝!
评论