Graph 迪克斯特拉';s算法来寻找所有可能的最短路径

Graph 迪克斯特拉';s算法来寻找所有可能的最短路径,graph,dijkstra,Graph,Dijkstra,我正在研究Dijkstra的算法,我真的需要找到所有可能的最短路径,而不仅仅是一条。我使用了一个邻接矩阵,我应用了Dijkstra算法,我可以找到最短路径。但我需要找到成本最低的所有路径,我指的是所有可能的解决方案,如果它们存在的话 对于单个解决方案,我的算法就是这样工作的: public void dijkstra( int graph[][] ) { int d[] = new int[ graph.length ]; int dC[] = new int[ graph.le

我正在研究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" );
}
public void dijkstra(int-graph[]
{
int d[]=新的int[graph.length];
int dC[]=新的int[graph.length];
int p[]=新的int[graph.length];
对于(int i=0;id[j]&&dC[j]!=-1){
min=d[j];pos=j;
}
}
dC[pos]=-1;
//放松
对于(int j=0;j图[pos][j]+d[pos]){
d[j]=图[pos][j]+d[pos];
p[j]=pos;
}
}
i++;最小值=200;
}
对于(int j=0;j
如果Dijkstra算法的实现基于优先级队列,则采用第一个解决方案,记录深度并不断弹出解决方案,直到深度发生变化。

如果您在此处查看伪代码形式的Dijkstra算法:


您将注意到称为Relax的线。现在,它只包含一个例子,说明找到的路径是否小于当前最短路径,但如果它们相等,则没有任何操作。您可能应该将所有同样短的路径都保存在一个列表中。

我不太确定Dijkstra的算法是否可以轻松地适应于此;当然,这并不像删除访问的边那么简单,因为n个最短的边可能共享其中一些边

因此,一种近乎蛮力的、但以启发式为导向的解决方案是尝试以下方法:

  • 对于最短路径中的每条边E:
    • 删除E并在新图形上再次运行修改后的Dijkstra
    • 如果最短路径比获得的第一条路径长,请停止
    • 否则,重复从新子图中一次递归删除一条边
我的直觉告诉我,它应该有效,复杂性的增加与第一个解决方案的长度(
n
边数)成正比。。。如果没有更多的最短路径,它应该在第一轮结束,如果找到另一条,它将继续进行
n-1
尝试。与原始算法相比,最坏情况下的复杂度增加估计是非常糟糕的(
n!
我猜是吧?),但这也意味着有很多路径,因此这是任何算法都需要完成的工作

编辑:再仔细想想,复杂性的增加可能比第一个找到的路径的节点数的阶乘还要大,因为第二个路径可能有更多的节点!所以我认为很难估计这个方法的复杂度,但它应该是有效解的数量乘以路径中节点的平均数量乘以节点数的平方(最后一项是未修改算法的原始复杂度)


编辑2:我发现了一篇关于这个主题的研究论文,需要订阅才能获得全文,但也许你可以在其他地方找到:

如果你的图允许权重为0的边,也允许循环,请记住有无限多条最短路径,你不能指望把它们全部输出

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

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

对于仅查找(等效)最短路径的受限问题,安德森·艾姆斯(Anderson Imes)在上面的提示(这是作业吗?否则应该有人把它拼出来)是很好的,并且比上面的提示简单得多。

描述了一种用于具有多维边权重的图的算法,该算法给出了所有最短路径

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

作者将它与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

JgraphT类查找所有最短路径。根据以上注释,您正在寻找两个顶点之间的最短路径。您可能需要使用方法,该方法将返回从一个顶点到所有其他顶点的所有最短路径。然后你可能想过滤你感兴趣的结果。

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

唯一的区别是如何从“父”和“距离”数组中提取信息

主要思想是

  • 您正在从目标移动到源,并从最佳路径(“父”数组)中的每个节点移动
  • 您正在寻找与源有相同最小距离的邻居,如记录的父对象,以及
  • 然后递归地遍历所有这些po
    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)