python Dijkstra 算法中图形总成本的困难

Difficulties with total cost of graph in Dijkstra algorithm in python

我目前正在尝试制作一种算法,当所有节点都已访问时,该算法会给出图形的总成本,但我悲惨地失败了,老实说是出于想法。我的目标是使用 Dijkstra 算法获得下图中的总成本。

这是我目前的情况:

from collections import defaultdict
import heapq

def build_graph():
    # Create the graph with the all given nodes and costs
    edges = aeroDistances
    graph = defaultdict(dict)

    for edge in edges.items():
        tuple1 = edge[0][0]
        tuple2 = edge[0][1]
        cost = edge[1]

        connection1 = {tuple2 : cost}
        connection2 = {tuple1 : cost}

        graph[tuple1].update(connection1)
        graph[tuple2].update(connection2)
    
    return dict(graph)

def dijkstra(graph, starting_vertex):
    # All the distances set to infinity
    distances = {vertex: float('infinity') for vertex in graph}
    # Distance from the starting vertex
    distances[starting_vertex] = 0
    # Priority queue
    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, distance

numCidades = 0
numAeroportos = 0
numEstradas = 0
#custoAeroportos = {}
#custoEstradas = {}

#custoAeroportos = {(1, 2): 2, (1, 3): 4}
#custoEstradas = {(3, 1, 'E'): 2}

#custoAeroportos = {(1, 2): 1, (2, 3): 2, (3, 4): 1, (4, 1): 1}
custoAeroportos = {(1, 2): 1, (1, 3): 6, (2, 4): 2, (3, 4): 2}
custoEstradas = {(2, 3): 3}

listCidades = [1,2,3]
distances = []
indexValue = 0
indexKey = 0
currentIndex = 0

# Deconstruct the dict into a list of keys (tuples)
# Deconstruct the dict into a list of values
# Make it easier to sort the connections by creating a list of tuples and
# their respective weights and zip them toghether
distancesAeroKeys = list(custoAeroportos.keys())
distancesAeroValues = list(custoAeroportos.values())
aeroDistances = dict(map(list, zip(*[distancesAeroKeys, distancesAeroValues])))

print()
print("AeroDistances: " + str(aeroDistances))

graph = build_graph()
print()
print("Graph: " + str(graph))
print()
print("Dijkstra: " + str(dijkstra(graph, 1)))

我目前正在尝试使用的两个图表、字典名为 custoAeroportos,当所有节点都被访问时,我似乎无法获得总的最低成本。

这是图表,它们相当简单:

This one has a total cost of 5

This one has a total cost of 3

我得到的总费用是错误的,我无法计算出来。

对于第一张图:

AeroDistances: {(1, 2): 1, (1, 3): 6, (2, 4): 2, (3, 4): 2}

Graph: {1: {2: 1, 3: 6}, 2: {1: 1, 4: 2}, 3: {1: 6, 4: 2}, 4: {2: 2, 3: 2}}

Dijkstra: ({1: 0, 2: 1, 3: 5, 4: 3}, 7)

对于第二张图,在某种程度上是正确的:

AeroDistances: {(1, 2): 1, (2, 3): 2, (3, 4): 1, (4, 1): 1}

Graph: {1: {2: 1, 4: 1}, 2: {1: 1, 3: 2}, 3: {2: 2, 4: 1}, 4: {3: 1, 1: 1}}

Dijkstra: ({1: 0, 2: 1, 3: 2, 4: 1}, 3)

非常感谢您的帮助,谢谢。

您的函数 return 是从起始顶点到添加到堆中的最后一个节点的路径的 distance。这真不是你想要的return。当然,当BFS-tree从某些顶点有多个出边时,这条路径与总距离关系不大。

相反,您需要累积“接受”的边的权重,即那些(隐含地)从堆中弹出的边并改进该节点的距离。

所以我建议使用更多信息扩展堆上的元组:将我们带到该节点的最后一条边的权重。当节点被接受时,这条边就成为生成树的一部分,然后它的权重应该被添加到一个累计总数中。

这是修改后的代码。这些更改附有评论:

def dijkstra(graph, starting_vertex):
    distances = {vertex: float('infinity') for vertex in graph}
    distances[starting_vertex] = 0
    graph_distance = 0  # this will be returned
    pq = [(0, 0, starting_vertex)]  # middle value is edge weight

    while len(pq) > 0:
        current_distance, edge_weight, current_vertex = heapq.heappop(pq)
        if current_distance > distances[current_vertex]:
            continue

        graph_distance += edge_weight  # accumulate

        for neighbor, weight in graph[current_vertex].items():
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, weight, neighbor))  # include weight

    return distances, graph_distance  # ...return it