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

发布于 2024-09-01 10:47:36 字数 1341 浏览 1 评论 0原文

我正在研究 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" );
}

I'm working on Dijkstra's algorithm, and I really need to find all the possible shortest paths, not just one. I'm using an adjacency matrix and I applied Dijkstra's algorithm, and I can find the shortest path. But I need to find all the paths with that minimum cost, I mean all the possible solutions, if they exist.

This is how my algorithm works, for a single solution:

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" );
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

ι不睡觉的鱼゛ 2024-09-08 10:47:36

如果您在这里以伪代码形式查看 Dijkstra 算法:
维基百科 Dijkstra 算法伪代码

您会注意到称为 Relax 的行。目前,它仅包含找到的路径小于当前最短路径的情况,但如果它们相等,则不会执行任何操作。您可能应该将所有同样短的路径保留在列表中。

If you look at Dijkstra's algorithm in pseudocode form here:
Wikipedia Dijkstra's Algorithm Pseudocode

You will notice the line referred to as a Relax. Right now it only contains a case for if the path found is less than the current shortest path, but there isn't anything done if they are equal. You should probably keep all the equally short paths in a List.

深居我梦 2024-09-08 10:47:36

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

If your implementation of Dijkstra's algorithm is based on a priority queue, take your first solution, record the depth and keep popping solutions out until the distance changes.

短暂陪伴 2024-09-08 10:47:36

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

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

这是解决稍微更普遍的问题的最佳来源:查找k 最短路径 (Eppstein)。您可以通过迭代最短路径来应用此方法,并在比前一条路径长的第一条路径处停止。

对于仅找到(等效)最短路径的受限问题,Anderson Imes 上面的提示(这是家庭作业吗?否则应该有人拼写出来)很好,并且比上面简单得多。

If your graphs allows edges with weight = 0 and also allows cycles, bear in mind that there are infinitely many shortest paths, and you cannot hope to output them all!

If there are either no zero-weight edges, or your graph is a DAG, then your solution is still problematic: it either doesn't produce all shortest paths as required, or it does so withO(2^N) space and time complexity. But then, perhaps there might be as many shortest paths, so you can not hope to do better in the general case.

This is the best source for a slightly more general problem: Finding the k Shortest Paths (Eppstein). You could apply this by iterating the shortest paths, stopping at the first path that is longer than the previous.

For the restricted problem of finding only the (equivalent) shortest paths, Anderson Imes' hint above (is this homework? Otherwise someone should spell it out) is good and much simpler than the above.

污味仙女 2024-09-08 10:47:36

我不太确定 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

I'm not very sure Dijkstra's algorithm can be easily adapted to do that; of course is not as simple as removing the visited edges, because the n shortest might share some of them.

So an almost brute force, but heuristically oriented solution, is to try this:

  • for every edge E in the shortest path:
    • remove E and run the modified Dijkstra again over the new graph
    • if the shortest path is longer than the first one obtained, stop
    • else, repeat recursively removing one edge at a time from the new sub-graph

My intuition tells me that it should work, with an increase in complexity proportional to the length (n in number of edges) of the first solution... If there are no more shortest path, it should end in the first round, if it founds another, it goes on with n-1 tries. The worst case complexity increase estimation over the original algorithm is very bad (n! I guess?), but that also means that there are lots of paths, so that is a work that needs to be done with any algorithm...

edit: Thinking a little bit more, the complexity increase might be even larger than the factorial of the number of nodes of the first found path, as the second might have even more nodes! So I think it's very difficult to estimate the complexity of this method, but it should be something like the number of valid solutions times the average number of nodes in the paths times the number of nodes squared (this last term being the original complexity of the unmodified algorithm).

edit 2: I've found a research paper about this subject, it requires subscription to get the full text but maybe you can find it somewhere else: 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

暗喜 2024-09-08 10:47:36

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

FloydWarshallShortestPaths class of JgraphT finds all shortest paths. Based on above comments, you are looking for shortest paths between two vertices. You may want to use getShortestPaths method, which will return all shortest paths from the a vertex to all other vertices. Then you may want to filter the result which interests you.

扛起拖把扫天下 2024-09-08 10:47:36

考虑这个算法: https://www.programmingalgorithms.com/algorithm/dijkstra's -算法/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;
                }

Consider this algorithm: https://www.programmingalgorithms.com/algorithm/dijkstra's-algorithm/php/
At the end there is a "< $distance[$v])" condition. If we change it to "<= ...", it will give all the existing shortest paths.

For collecting the paths we can put a

$this->paths[$v][] = $u;
row here also.
The whole snippet is here: 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;
                }
征棹 2024-09-08 10:47:36

这篇 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

This paper from 1982 describes an algorithm for graphs with multi-dimensional edge weights, that gives all shortest paths.

The algorithm works fine with simple weighted graphs, so should work for your case.

The author compares it to Dijkstra, both in how it works and in a run-time complexity comparison.

In pseudocode, paraphrasing the paper:

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
酒解孤独 2024-09-08 10:47:36

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

唯一的区别是如何从“parents”和“distances”数组中提取信息。

主要思想是

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

下面是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)

I Just solved a task to find all possible shortest paths on leetcode.com using Dijkstra's algorithm.

The only difference is how you extract information from "parents" and "distances" arrays.

The main idea is

  • you are moving from target to source and from each node in your optimal path ("parents" array),
  • you are looking for neighbors who had same minimal distances to the source like recorded parent, and
  • then recursively moving through all of those possible parents till you reach the source.

Below is the code in 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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文