zoukankan      html  css  js  c++  java
  • 带有负权边的最短路径问题

    2018-03-13 17:08:57

    最短路径问题是图论中一个经典的问题,Dijkstra算法更是大名鼎鼎。然而纵是如此著名的算法也有其不擅长的领域,也就是带有负权边的图是无法使用Dijkstra算法来进行最短路计算的。理由也很简单,每次dijkstra都是将目前的额最短路添加到集合中,这也就保证了,下一次的最短路径是肯定要长于之前添加进去的最短路径的,然而在有负权边的时候,这个推论就会被打破,最后会导致整个Dijkstra算法崩溃。

    那么,难道带有负权边的最短路径问题就没有解法了么?

    答案显然是否定的,这里就会介绍两种求解带有负权边的图的最短路径求解的算法,一是Bellman Ford算法,二是SPFA算法

    一、Bellman Ford算法

    贝尔曼-福特算法(英语:Bellman–Ford algorithm),求解单源最短路径问题的一种算法,由理查德·贝尔曼(Richard Bellman) 和 莱斯特·福特 创立的。有时候这种算法也被称为 Moore-Bellman-Ford 算法,因为Edward F. Moore 也为这个算法的发展做出了贡献。它的原理是对图进行V-1次松弛操作,得到所有可能的最短路径。其优于迪科斯彻算法的方面是边的权值可以为负数、实现简单,缺点是时间复杂度过高,高达O(VE)。但算法可以进行若干种优化,提高了效率。

    Bellman Ford算法每次对所有的边进行松弛,每次松弛都会得到一条最短路径,所以总共需要要做的松弛操作是V - 1次。在完成这么多次松弛后如果还是可以松弛的话,那么就意味着,其中包含负环。

    procedure BellmanFord(list vertices, list edges, vertex source)
       // 该实现读入边和节点的列表,并向两个数组(distance和predecessor)中写入最短路径信息
    
       // 步骤1:初始化图
       for each vertex v in vertices:
           if v is source then distance[v] := 0
           else distance[v] := infinity
           predecessor[v] := null
    
       // 步骤2:重复对每一条边进行松弛操作
       for i from 1 to size(vertices)-1:
           for each edge (u, v) with weight w in edges:
               if distance[u] + w < distance[v]:
                   distance[v] := distance[u] + w
                   predecessor[v] := u
    
       // 步骤3:检查负权环
       for each edge (u, v) with weight w in edges:
           if distance[u] + w < distance[v]:
               error "图包含了负权环"
    

    二、SPFA算法

    求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm。 SPFA算法是西南交通大学段凡丁于1994年发表的。松弛操作必定只会发生在最短路径前导节点松弛成功过的节点上,用一个队列记录松弛过的节点,可以避免了冗余计算。复杂度可以降低到O(kE),k是个比较小的系数(并且在绝大多数的图中,k<=2,然而在一些精心构造的图中可能会上升到很高)。

    SPFA算法可以认为是对Bellman Ford算法的优化,但不论如何,这是在最短路径问题中由中国学生提出的算法,算法的核心思路并不复杂,主要的操作就是维护一个candidate队列,最开始的时候只有s,然后对s的邻接边进行松弛,如果可以松弛,则判断一下当前结点是否在队列中,如果不在的话,那么将该结点加入队列,重复操作,知道队列为空。

    从理性的角度来分析这个算法的合理性:

    只要最短路径存在,上述SPFA算法必定能求出最小值。证明:每次将点放入队尾,都是经过松弛操作达到的。换言之,每次的优化将会有某个点v的最短路径估计值d[v]变小。所以算法的执行会使d越来越小。由于我们假定图中不存在负权回路,所以每个结点都有最短路径值。因此,算法不会无限执行下去,随着d值的逐渐变小,直到到达最短路径值时,算法结束,这时的最短路径估计值就是对应结点的最短路径值。

    SPFA判环:

    当一个结点入队次数到达V的时候,表明其中有环。如同Bellman Ford算法,只需要V - 1次就可以完成所有的松弛,如果做了 V 次松弛,那么说明有环。

    具体实现中可以用一个数组保存每个结点的入队次数。

     procedure Shortest-Path-Faster-Algorithm(G, s)
      1    for each vertex v ≠ s in V(G)
      2        d(v) := ∞
      3    d(s) := 0
      4    offer s into Q
      5    while Q is not empty
      6        u := poll Q
      7        for each edge (u, v) in E(G)
      8            if d(u) + w(u, v) < d(v) then
      9                d(v) := d(u) + w(u, v)
     10                if v is not in Q then
     11                    offer v into Q
    

  • 相关阅读:
    网站性能在线评估
    如何测试电梯/伞/桌子/笔?
    apk反编译查看源码
    Jmeter(四)-断言/检查点
    【转】Jmeter(三)-简单的HTTP请求(非录制)
    【转】Jmeter(二)-使用代理录制脚本
    [转]Jmeter(一)-精简测试脚本
    CentOS 安装以及配置Apache php mysql
    centOS静态ip设置
    免费DDOS攻击测试工具大合集
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/8559241.html
Copyright © 2011-2022 走看看