Kruskal 最小生成树 & Dijkstra 最短路径
来源:互联网 发布:mpp数据库类型 编辑:程序博客网 时间:2024/06/06 05:08
最小生成树的另一种算法——Kruskal 算法。首先我们定义带权图 G 的边集合为 E,接着我们再定义最小生成树的边集合为 T,初始集合 T 都为空。接着执行以下操作:
首先,我们把图 G 看成一个有 n 棵树的森林,图上每个顶点对应一棵树。
接着,我们将边集合 E 的每条边,按权值从小到大进行排序,
依次遍历每条边 e = (u, v),我们记顶点 u 所在的树为 Tu ,顶点 v所在的树为 Tv,如果 Tu 和 Tv 不是同一棵树,则我们将边 e 加入集合 T,并将两棵树 Tu和 Tv进行合并。
算法执行完毕后,集合 T 记录了最小生成树的所有边。
仔细分析算法,我们可以发现,Kruskal 算法也是采用了贪心的策略,每次都会选择一条两个顶点不在同一棵树且权值最小的边加入集合。Kruskal 算法的时间复杂度为 O(ElogE),E 为图 G 的总边数,所以 Kruskal 算法一般应用于较为稀疏的图,也就是顶点较多、而边较少的图。
图论的另一个问题——最短路问题。什么是最短路问题呢?我们先来看这样一个问题:
有 n座城市,已知任意两座城市之间的距离,现在要分别求出城市 A 到其他 n - 1 座城市的最短路径,也就是求所经过的距离和的最小值。
这是一个经典的单源最短路问题,即求一起点到其余各个顶点的最短路径问题。
首先我们可以把该场景看成是一个带权图,把 n 个城市看成 n 个顶点,把两座城市之间的距离看成是两个顶点之间的边权值,这样问题就转化成了求顶点 A到其余 n - 1个顶点的最短路径。
Dijkstra 算法是常见的求解单源最短路问题的算法,我们将在后面详细讲述 Dijkstra 算法。
我们先来看看 Dijkstra 算法的具体过程:
我们定义带权图 G 所有顶点的集合为V,接着我们再定义已确定最短路径的顶点集合为 U,初始集合 U 为空。接着执行以下操作:
首先我们将起点 x 加入集合 U,并在数组 A 中记录起点 x 到各个点的最短路径(如果顶点到起点 x 有直接相连的边,则最短路径为边权值,否则为一个极大值)。
从数组 A 中选择一个距离起点 x 最近的、且不属于集合 U 的顶点 v(如果有多个顶点 v,任选其一即可),将顶点 v 加入集合 U,并更新所有与顶点 v 相连的顶点到起点 x 的最短路径。
重复第二步操作,直至集合 U 等于集合 V。
仔细分析算法,我们可以发现,Dijkstra 算法和前面讲解的 Prim 算法很相像,都是从一个点开始,每次确定一个点并完成更新,重复操作直至 n 个点都确定为止。Dijkstra 算法的时间复杂度为 O(V^2+E),V 为顶点总个数,E 为总边数。如果利用堆进行优化,可以将时间复杂度优化 O(VlogV+E),是最坏情况下最优的单源最短路算法。
需要注意的是,Dijkstra 不适用于有边权为负数的情况哦,否则会影响算法的正确性。
#include <vector>#include <queue>using namespace std;const int INF = 0x3f3f3f3f;struct Edge { int vertex, weight;};class Graph {private: int n; vector<Edge> * edges; bool * visited;public: int * dist; Graph (int input_n) { n = input_n; edges = new vector<Edge>[n]; dist = new int[n]; visited = new bool[n]; memset(visited, 0, n); memset(dist, 0x3f, n * sizeof(int)); } ~Graph() { delete[] dist; delete[] edges; delete[] visited; } void insert(int x, int y, int weight) { edges[x].push_back(Edge{y, weight}); edges[y].push_back(Edge{x, weight}); } void dijkstra(int v) { //v是源点 dist[v]=0; for(int i=0;i<n;i++){ int min_dist=INF,min_vertex; for(int j=0;j<n;++j){ if(!visited[j]&&dist[j]<min_dist){ min_dist=dist[j]; min_vertex=j; } } visited[min_vertex]=1; //松弛操作 for(Edge &j:edges[min_vertex]){ //与min_vertex结点相连的结点遍历 //更新相邻点的最短距离 if(min_dist+j.weight<dist[j.vertex]){ dist[j.vertex]=min_dist+j.weight; } } } }};int main() { int n, m; cin >> n >> m; Graph g(n); for (int i = 0; i < m; i++) { int a, b, c; cin >> a >> b >> c; g.insert(a, b, c); } g.dijkstra(0); for (int i = 0; i < n; i++) { cout << i << ": " << g.dist[i] << endl; } return 0;}
- Kruskal 最小生成树 & Dijkstra 最短路径
- 图(Graph)——最小生成树、最短路径、Kruskal、Dijkstra、Floyd
- 最小生成树算法(Prime、Kruskal)和最短路径算法(Dijkstra、Floyd)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 图(Graph)——最小生成树、最短路径、Kruskal、Dijkstra、Floyd
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)
- 初试编程+算法
- Spring 之IOC容器(初级)
- 合并查询结果 与 表的别名
- 微电网和主动配电网
- AVR Studio中AVR学习之ADC转换
- Kruskal 最小生成树 & Dijkstra 最短路径
- 排序算法总结(一)
- linux 2.6内核 编译模块Makefile 详解
- 当谨慎变成了常态
- 节点带有属性的xml pull解析
- 在Linux下使用MySQl遇到的小问题集合
- java线程
- HttpURLConnection 的get请求
- Linux sudo一些命令出现 command not found 的原因