Kruskal 最小生成树 & Dijkstra 最短路径

原创 2016年06月01日 21:53:19

最小生成树的另一种算法——Kruskal 算法。首先我们定义带权图 G 的边集合为 E,接着我们再定义最小生成树的边集合为 T,初始集合 T 都为空。接着执行以下操作:

首先,我们把图 G 看成一个有 n 棵树的森林,图上每个顶点对应一棵树。

接着,我们将边集合 E 的每条边,按权值从小到大进行排序,

依次遍历每条边 e = (u, v),我们记顶点 u 所在的树为 T​u​​ ,顶点 v所在的树为 T​v,如果 T​u 和 T​v 不是同一棵树,则我们将边 e 加入集合 T,并将两棵树 T​u和 T​v进行合并。

算法执行完毕后,集合 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;
}
版权声明:ShirleyPaul原创,未经博主允许不得转载

相关文章推荐

算法篇-7-贪心算法-Huffman编码&Dijkstra单源最短路径&Kruskal最小生成树

本系列所有代码https://github.com/YIWANFENG/Algorithm-github huffman编码 题目: 依据给定字符以及相应频率构造该字符的哈夫曼编码。   算法思路分...

图(Graph)——最小生成树、最短路径、Kruskal、Dijkstra、Floyd

4. 最小生成树 4.1 生成树 (1)定义:所有顶点均由边连接在一起,但不存在回路的图叫该图的生成树 (2)深度优先生成树与广度优先生成树 (3)     一个图可以有许多棵不同的生成树     所...
  • xiyanlgu
  • xiyanlgu
  • 2013年09月21日 19:50
  • 12787

浅析最小生成树和单源最短路径的区别(含Prim、Kruskal、Dijkstra、Bellman-Ford)

一切还是源于最近布置的wsn作业。作业要求以Dijkstra算法实现从源节点到其他节点的最短路径。问题是图是个**无向图**,DIjkstra在我印象中只针对**有向图**。我立马就凌乱了,一直凌乱到...
  • ds1231h
  • ds1231h
  • 2017年04月16日 19:56
  • 396

最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)

文章转自:http://www.cnblogs.com/aiyelinglong/archive/2012/03/26/2418707.html 简介: 带权图分为有向和无向,无向图的最短...

POJ1797 Heavy Transportation (最短路径/最小生成树kruskal)

本文出自:http://blog.csdn.net/svitter 原题连接:http://poj.org/problem?id=1797 题意:找出一条从1 ~ n的所有的路径中权值最小的那条路...
  • svitter
  • svitter
  • 2014年04月26日 16:16
  • 1091

最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)

带权图分为有向和无向,无向图的最短路径又叫做最小生成树,有prime算法和kruskal算法;有向图的最短路径算法有dijkstra算法和floyd算法。   生成树的概念:联通图G的一个子图如果是...

最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)

带权图分为有向和无向,无向图的最短路径又叫做最小生成树,有prime算法和kruskal算法;有向图的最短路径算法有dijkstra算法和floyd算法。   生成树的概念:联通图G的一个子图如...

最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)

转载自:http://www.cnblogs.com/aiyelinglong/archive/2012/03/26/2418707.html 带权图分为有向和无向,无向图的最短路径又叫做最小生...
  • phiall
  • phiall
  • 2016年03月21日 22:20
  • 486

最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)

原文地址请点击 带权图分为有向和无向,无向图的最短路径又叫做最小生成树,有prime算法和kruskal算法;有向图的最短路径算法有dijkstra算法和floyd算法。   生成树的概念:联...

最小生成树(prime算法、kruskal算法) 和 最短路径算法(floyd、dijkstra)(转)

原网址 带权图分为有向和无向,无向图的最短路径又叫做最小生成树,有prime算法和kruskal算法;有向图的最短路径算法有dijkstra算法和floyd算法。  生成树的概念:联通图G的一个子图...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Kruskal 最小生成树 & Dijkstra 最短路径
举报原因:
原因补充:

(最多只允许输入30个字)