• ⑨讲图论第四课: Dijkstra算法求最短路


    迪科斯彻算法(英语:Dijkstra's algorithm)是由荷兰计算机科学家艾兹赫尔·戴克斯特拉(Edsger Wybe Dijkstra)发明的。算法解决的是有向图中单个源点到其他顶点的最短路径问题。举例来说,如果图中的顶点表示城市,而边上的权重表示著城市间开车行经的距离,该算法可以用来找到两个城市之间的最短路径。

    算法描述

    该算法的输入包含了一个有权重的有向图 G,以及G中的一个来源顶点 S。我们以 V 表示 G 中所有顶点的集合。每一个图中的边,都是两个顶点所形成的有序元素对。(u, v) 表示从顶点 u 到 v 有路径相连。我们以 E 所有边的集合,而边的权重则由权重函数 w: E → [0, ∞] 定义。因此,w(u, v) 就是从顶点 u 到顶点 v 的非负权重(weight)。边的权重可以想像成两个顶点之间的距离。任两点间路径的权重,就是该路径上所有边的权重总和。已知有 V 中有顶点 s 及 t,Dijkstra 算法可以找到 s 到 t 的最低权重路径(例如,最短路径)。这个算法也可以在一个图中,找到从一个顶点 s 到任何其他顶点的最短路径。


    这个算法是通过为每个顶点 v 保留目前为止所找到的从s到v的最短路径来工作的。初始时,原点 s 的路径长度值被赋为 0 (d[s] = 0),若存在能直接到达的边(s,m),则把d[m]设为w(s,m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大,即表示我们不知道任何通向这些顶点的路径(对于 V 中所有顶点 v 除 s 和上述 m 外 d[v] = ∞)。当算法退出时,d[v] 中存储的便是从 s 到 v 的最短路径,或者如果路径不存在的话是无穷大。 Dijkstra 算法的基础操作是边的拓展:如果存在一条从 u 到 v 的边,那么从 s 到 v 的最短路径可以通过将边(u, v)添加到尾部来拓展一条从 s 到 u 的路径。这条路径的长度是 d[u] + w(u, v)。如果这个值比目前已知的 d[v] 的值要小,我们可以用新值来替代当前 d[v] 中的值。拓展边的操作一直运行到所有的 d[v] 都代表从 s 到 v 最短路径的花费。这个算法经过组织因而当 d[u] 达到它最终的值的时候每条边(u, v)都只被拓展一次。


    算法维护两个顶点集 S 和 Q。集合 S 保留了我们已知的所有 d[v] 的值已经是最短路径的值顶点,而集合 Q 则保留其他所有顶点。集合S初始状态为空,而后每一步都有一个顶点从 Q 移动到 S。这个被选择的顶点是 Q 中拥有最小的 d[u] 值的顶点。当一个顶点 u 从 Q 中转移到了 S 中,算法对每条外接边 (u, v) 进行拓展。

    伪代码

    在下面的算法中,u := Extract_Min(Q) 在顶点集合 Q 中搜索有最小的 d[u] 值的顶点 u。这个顶点被从集合 Q 中删除并返回给用户。

    伪代码描述:

      function Dijkstra(G, w, s)
         for each vertex v in V[G]        // 初始化
               d[v] := infinity           // 将各点的已知最短距离先设置成无穷大
               previous[v] := undefined   // 各点的已知最短路径上的前趋都未知
         d[s] := 0                        // 因为出发点到出发点间不需移动任何距离,所以可以直接将s到s的最小距离设为0
         S := empty set
         Q := set of all vertices
         while Q is not an empty set      // Dijkstra演算法主體
               u := Extract_Min(Q)
               S.append(u)
               for each edge outgoing from u as (u,v)
                      if d[v] > d[u] + w(u,v)     // 拓展边(u,v)。w(u,v)为从u到v的路径长度。
                            d[v] := d[u] + w(u,v) // 更新路径长度到更小的那个和值。
                            previous[v] := u      // 记录前趋顶点
    C++描述(采用邻接矩阵存图)
    int dijkstra(int s,int t)
    {
        int min_d,m;
        for (int i=1; i<=n; i++)
        {
            d[i]=OO;//将各点的已知最短距离先设置成无穷大
            v[i]=false;//表示所有点都在集合Q,此时集合S为空
            pre[i]=0;//各点的已知最短路径上的前趋都未知
        }
        d[s]=0;//因为出发点到出发点间不需移动任何距离,所以可以直接将s到s的最小距离设为0
        for (int lp=1; lp<=n; lp++)//Dijkstra算法主体
        {
            min_d=OO;
            for (int i=1; i<=n; i++)
            {
                if (!v[i]&&d[i]<min_d)//寻找集合Q中最小的d[m]
                {
                    min_d=d[i];
                    m=i;
                }
            }
            v[m]=true;//将点m从集合Q移动到集合S
            for (int i=1; i<=n; i++)
            {
                if (!v[i]&&d[m]+a[m][i]<d[i])
                {
                    d[i]=d[m]+a[m][i];//更新从s到i的最短路
                    pre[i]=m;//记录前趋
                }
            }
        }
        return d[t];
    }
    


    通过推导可知,为了记录最佳路径的轨迹,我们只需记录该路径上每个点的前趋,即可通过迭代来回溯出 s 到 t 的最短路径(当然,使用后继节点来存储亦可。但那需要修改代码)

    注意:如果图有负权边,那么dijkstra算法将会失效。

  • 相关阅读:
    Suricata的输出
    Setting up IPS/inline for Linux in Suricata
    Suricata的初始化脚本
    Suricata的Reputation
    Suricata的配置
    Suricata的性能
    Suricata里的规则与Snort区别之处
    Suricata的命令行解释
    [转]ASP.NET 成员资格 Part.1(API)
    [转]ASP.NET MVC4+BootStrap 实战(一)
  • 原文地址:https://www.cnblogs.com/cyendra/p/3038396.html
Copyright © 2020-2023  润新知