Dijkstra的算法可以找到所有可能的最短路径

时间:2010-05-12 13:45:16

标签: graph dijkstra

我正在研究Dijkstra的算法,我真的需要找到所有可能的最短路径,而不仅仅是一条路径。我正在使用邻接矩阵,我应用了Dijkstra算法,我可以找到最短路径。但我需要找到具有最低成本的所有路径,我指的是所有可能的解决方案,如果存在的话。

对于单一解决方案,这就是我的算法的工作方式:

public void dijkstra( int graph[][] )
{
    int d[] = new int[ graph.length ];
    int dC[] = new int[ graph.length ];
    int p[] = new int[ graph.length ];

    for( int i = 0; i < graph.length; i++ ){
        d[ i ] = 100; dC[ i ] = 100; p[ i ] = -1;
    }
    d[ 0 ] = 0; dC[ 0 ] = 0;

    int i = 0, min = 200, pos = 0; //You can change the min to 1000 to make it the largest number
    while( i < graph.length ){
        //extract minimum
        for( int j = 0; j < dC.length; j++ ){
            if( min > d[ j ] && dC[ j ] != -1 ){
                min = d[ j ]; pos = j;
            }
        }
        dC[ pos ] = -1;

        //relax
        for( int j = 0; j < graph.length; j++ ){
            if( d[ j ] > graph[ pos ][ j ] + d[ pos ] ){
                d[ j ] = graph[ pos ][ j ] + d[ pos ];
                p[ j ] = pos;
            }
        }
        i++; min = 200;
    }

    for( int j = 0; j < p.length; j++ ){
        System.out.print( p[ j ] + " " );
    }
    System.out.print( "\n" );
    for( int j = 0; j < d.length; j++ ){
        System.out.print( d[ j ] + " " );
    }
    System.out.print( "\n" );
}

8 个答案:

答案 0 :(得分:13)

如果你在这里以伪码形式查看Dijkstra的算法: Wikipedia Dijkstra's Algorithm Pseudocode

您会注意到被称为Relax的行。现在它只包含一个案例,如果找到的路径小于当前最短路径,但如果它们相等则没有任何事情。您应该在列表中保留所有相同的短路径。

答案 1 :(得分:3)

如果您对Dijkstra算法的实施基于优先级队列,请采用您的第一个解决方案,记录深度并保持弹出解决方案,直到深度发生变化。

答案 2 :(得分:3)

如果您的图表允许带有weight = 0的边并且还允许循环,请记住,有无限多个最短路径,并且您不能希望将它们全部输出!

如果没有零权重边缘,或者您的图表是DAG,那么您的解决方案仍然存在问题:它要么根据需要不生成所有最短路径,要么就是这样做O(2^N)空间和时间复杂度。但是,也许可能会有尽可能多的最短路径,所以你不能希望在一般情况下做得更好。

这是一个稍微更普遍的问题的最佳来源:Finding the k Shortest Paths(Eppstein)。您可以通过迭代最短路径来应用此功能,停止在比前一个路径更长的第一条路径上。

对于仅找到(等效的)最短路径的限制性问题,Anderson Imes的上述暗示(这是作业吗?否则有人应该将其拼写出来)比上述更好,更简单。

答案 3 :(得分:1)

考虑这个算法:https://www.programmingalgorithms.com/algorithm/dijkstra's-algorithm/php/ 最后有一个“< $distance[$v])”条件。如果我们将其更改为“<= ...”,它将给出所有现有的最短路径。

为了收集路径,我们可以放一个

$this->paths[$v][] = $u; 排这里也。 整个片段在这里:https://pastebin.com/gk2ymyWw

                if (!$this->known[$v] && $graph[$u][$v] && $this->distance[$u] != $this->INT_MAX && $this->distance[$u] + $graph[$u][$v] <= $this->distance[$v]) {
                    $this->distance[$v] = $this->distance[$u] + $graph[$u][$v];
                    $this->paths[$v][] = $u;
                }

答案 4 :(得分:0)

我不太确定Dijkstra的算法可以很容易地适应这种情况;当然不像删除访问边缘那么简单,因为n最短的可能共享一些

所以一个几乎是暴力的力量,但启发式的解决方案,是尝试这个:

  • 对于最短路径中的每个边E:
    • 删除E并在新图表上再次运行修改后的Dijkstra
    • 如果最短路径长于获得的第一条路径,请停止
    • 否则,从新的子图
    • 一次重复递归删除一条边

我的直觉告诉我它应该有效,复杂度的增加与第一个解决方案的长度(n边缘数量)成正比...如果没有更短的路径,它应该结束在第一轮中,如果它找到了另一个,它会继续n-1次尝试。最坏情况复杂度增加估计超过原始算法非常糟糕(n!我猜?),但这也意味着有很多路径,所以这是一项需要用任何算法完成的工作..

编辑多思考一下,复杂性的增加可能比第一个找到的路径的节点数的因子大,因为第二个可能有更多的节点!所以我认为估计这种方法的复杂性是非常困难的,但它应该像有效解决方案的数量乘以路径中的平均节点数乘以节点平方数(最后一次)术语是未修改算法的原始复杂性。)

编辑2:我发现了一篇关于这个主题的研究论文,需要订阅才能获得全文,但也许你可以在其他地方找到它:http://ieeexplore.ieee.org/Xplore/login.jsp?reload=true&url=http%3A%2F%2Fieeexplore.ieee.org%2Fiel5%2F7719%2F21161%2F00982778.pdf%3Farnumber%3D982778&authDecision=-201

答案 5 :(得分:0)

This paper from 1982描述了具有多维边权重的图的算法,该算法给出了所有最短路径。

该算法适用于简单的加权图,因此适用于您的情况。

作者将它与Dijkstra进行了比较,包括它的工作原理和运行时复杂性比较。

在伪代码中,解释论文:

1. H is a heap of paths sorted on the weights of these paths, either
     a. lexicographically and decreasing in each element of the weight vector
     b. on the negative sum of all the elements in the weight vector
   Initially, H contains only path p0 (the starting point) the weight of which is O.
2. S1 through Sv are sets associated with vertices v1 through vv respectively.
   These sets contain the maximal paths to each vertex, as they are discovered.
   Initially, all sets are empty.
3. a. While (H is not empty) do begin
   b.   remove the root of H, p;
   c.   if p is not dominated by any of the paths in Sn where vn is last vertex of p
   d.     add it to Sn (the set of maxima for vertex vn)
   e.     for each possible extensions q of path p
   g.       if path q to node vm is not yet dominated by the maxima in Sm
   h.         insert q into H

答案 6 :(得分:0)

JgraphT的

FloydWarshallShortestPaths类找到所有最短路径。基于以上注释,您正在寻找两个顶点之间的最短路径。您可能希望使用getShortestPaths方法,该方法将返回从顶点到所有其他顶点的所有最短路径。那么您可能想要过滤您感兴趣的结果。

答案 7 :(得分:0)

我刚刚使用Dijkstra算法解决了在leetcode.com上找到所有可能的最短路径的任务。

唯一的区别是你如何从父母那里提取信息&#34;和#34;距离&#34;阵列。

主要想法是

  • 您正在从目标移动到源和最佳路径中的每个节点(&#34;父母&#34;数组),
  • 你正在寻找与记录的父母和
  • 之间距离相同的最小距离的邻居
  • 然后递归地移动所有可能的父母,直到你到达源头。

以下是Python中的代码。

if parent[endNode] > -1: # -1 means no path at all
            self.traversingAllNodes(parents, shortestDistances, endNode, [endNode])
    return self.finalList

def traversingAllNodes(self, parents, distances, startNode, path):
    if parents[startNode] == -1:
        self.saveFound(path) # saving one path
        return
    currentNode = startNode
    parent = parents[currentNode] # recorded parent
    optimalDistance = distances[parent] # distance from parent to source
    for node in self.graph[currentNode]: # moving via neighbords
        if distances[node] == optimalDistance: 
            path.append(node)
            self.traversingAllNodes(parents, distances, node, path)
            path.remove(node)