为什么此Dijkstra代码正确(节点处理)?

时间:2019-09-12 21:23:17

标签: dijkstra

https://bradfieldcs.com/algos/graphs/dijkstras-algorithm/

我不太明白为什么这是真的。他们声称,通过检查current_distance > distances[current_vertex],我们可以准确地处理每个节点一次。但是,这对我来说并不正确,因为while循环的最后两行是

distances[neighbor] = distance
heapq.heappush(pq, (distance, neighbor))

因此,我认为每次将节点推入堆时,如果再次将其弹出,并且我们观察到current_vertex, current_vertex(弹出的节点和权重),则distance [neighbor]将等于current_distance。因此,该节点将得到重新处理,并且不会像以前声明的那样被跳过。

import heapq


def calculate_distances(graph, starting_vertex):
    distances = {vertex: float('infinity') for vertex in graph}
    distances[starting_vertex] = 0

    pq = [(0, starting_vertex)]
    while len(pq) > 0:
        current_distance, current_vertex = heapq.heappop(pq)

        # Nodes can get added to the priority queue multiple times. We only
        # process a vertex the first time we remove it from the priority queue.
        if current_distance > distances[current_vertex]:
            continue

        for neighbor, weight in graph[current_vertex].items():
            distance = current_distance + weight

            # Only consider this new path if it's better than any path we've
            # already found.
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, neighbor))

    return distances

有人可以告诉我我在这里想念的吗?我知道每个节点只应处理一次,但我不明白为什么该代码如此处理。而且我看不到哪里错了。

1 个答案:

答案 0 :(得分:1)

可以将顶点多次添加到堆中。每次将其添加到具有不同距离的堆中。现在,您终于可以处理它了。由于它是优先级队列,因此您将处理一对(vertex, distance),且距离最短。

两个想法:

  1. 对于每个顶点,只能处理现有(存在于堆中)对中的一对。
  2. 处理完顶点后,将不再为此顶点添加新对。

首先,到顶点的距离总是减小。这意味着对于给定的顶点,只有一个(vertex, distance)可以被触发:即距离最小的一个(除非稍后到达距离更小的一对)。换句话说,当顶点被处理时,堆中的所有其他对将不会被处理。

顶点处理后,其距离无法更改。原因是Dijkstra选择了距离最小的顶点。并且由于所有边缘权重均为正,并且所有其他顶点具有更大的距离,因此到处理的顶点的距离不会减小。因此,顶点对不会出现在堆中。