对于 Dijkstra 的算法,有啥方法可以跟踪和存储每条最短路径包含的顶点?

Posted

技术标签:

【中文标题】对于 Dijkstra 的算法,有啥方法可以跟踪和存储每条最短路径包含的顶点?【英文标题】:For Dijkstra's algorithm, what would be a way to keep track of and store the vertices that each shortest path contains?对于 Dijkstra 的算法,有什么方法可以跟踪和存储每条最短路径包含的顶点? 【发布时间】:2022-01-07 18:20:28 【问题描述】:

我已将其编码以更新边的所有成本,以完成 Dijkstra 的主要目标,即找到从源顶点到所有其他顶点的最短路径。

但我需要帮助的是想办法将每个最短路径包含的顶点存储到一个数组中,该数组包含它通过的每个路径的顶点。

例如,假设从源顶点 (A) 到顶点 (Z) 的最短路径是 A - > B - > V - > Z。最短路径经过顶点B和V以获得Z。我希望能够将该序列中的每个顶点存储到一个数组中。然后将该数组放入更大的数组列表中,该列表将包含所有序列。问题是我不确定将其放置在哪里,因为下面的 while 循环用于更新边缘的成本。

from queue import PriorityQueue

class Graph:

    def __init__(self, num_of_vertices):
        self.v = num_of_vertices
        self.edges = [[-1 for i in range(num_of_vertices)] for j in range(num_of_vertices)]
        self.visited = []
        
    def add_edge(self, u, v, weight):
        self.edges[u][v] = weight
        self.edges[v][u] = weight
        
    def dijkstra(self, start_vertex):
        D = v:float('inf') for v in range(self.v)
        V = v:None for v in range(self.v)
        D[start_vertex] = 0
        
        pq = PriorityQueue()
        pq.put((0, start_vertex))
        
        AllPathsList = []
        
        while not pq.empty():
            (dist, current_vertex) = pq.get()
            self.visited.append(current_vertex)

            for neighbor in range(self.v):
                if self.edges[current_vertex][neighbor] != -1:
                    distance = self.edges[current_vertex][neighbor]
                    if neighbor not in self.visited:
                        old_cost = D[neighbor]
                        new_cost = D[current_vertex] + distance
                        if new_cost < old_cost:
                            pq.put((new_cost, neighbor))
                            D[neighbor] = new_cost
                            V[neighbor] = current_vertex          
            S = []
            u = current_vertex
            while V[u] != None:
                S.insert(0, u)
                u = V[u]
                
            S.insert(0, start_vertex)
            AllPathsList.append(S)
            
        return D, AllPathsList
        
def main():
    g = Graph(6)
    g.add_edge(0, 1, 4)
    g.add_edge(0, 2, 7)
    g.add_edge(1, 2, 11)
    g.add_edge(1, 3, 20)
    g.add_edge(3, 4, 5)
    g.add_edge(3, 5, 6)
    g.add_edge(2, 3, 3)
    g.add_edge(2, 4 ,2)
    
    D, AllPathsList = g.dijkstra(0)

    for vertex in range(len(D)):
        print("Distance from vertex 0 to vertex", vertex, "is:", D[vertex])
        print("Particular path is:", AllPathsList[vertex])
main()

【问题讨论】:

您可以将它们与坐标一起存储,比如一个元组,然后在创建它们时添加它+由最后一条路径表示的先前节点。 【参考方案1】:

通常的程序是跟踪每个顶点的前驱。每次更新顶点的成本时,都会将您从那里获得的顶点存储为它的前身。

当你完成后,你可以沿着从任何顶点到源头的前辈链来找到它的最短路径。

【讨论】:

如果你想要所有相等的路径,你可以存储多个前辈——当你得到一个相等的距离时追加一个新的,当你得到一个较短的路径时用一个新的替换整个组。跨度> @Matt Timmermans 我在将所有顶点初始化为无穷大后添加了V = v:None for v in range(self.v),在将邻居设置为新成本后添加了V[neighbor] = current_vertex。我相信这得到了你在第一部分中所说的。那我怎么跟上前辈的链条呢? 我在 for 循环之后添加了S = [] u = neighbor while V[u] != None: S.append(u) u = V[u],因为这篇文章的最佳答案暗示了***.com/questions/28998597/…,但我不相信我做得对。 @tridentzx 你可能想在末尾反转S 并添加start_vertex。也从current_vertex 开始,而不是neighbor。否则看起来是正确的。 @MattTimmermans 我更新了上面的代码,这就是图表的样子,imgur.com/a/NC8QmP3,但是,由于某种原因,其中两条路径被切换了。从代码给出的输出和图表可以看出,输出的从顶点0到3的路径和从顶点0到4的路径应该是切换的。

以上是关于对于 Dijkstra 的算法,有啥方法可以跟踪和存储每条最短路径包含的顶点?的主要内容,如果未能解决你的问题,请参考以下文章

使用最小优先级队列时,如何跟踪 Dijkstra 算法中的最短路径?

Dijkstra算法详细(单源最短路径算法)

OSPF的算法是啥

(单源最短路径)一文搞懂dijkstra算法

有啥方法可以跟踪数据库中oracle函数插入的行

图论——关于Dijkstra的贪心思想