【问题标题】:Difficulties with total cost of graph in Dijkstra algorithm in pythonpython中Dijkstra算法中图形总成本的困难
【发布时间】:2021-12-30 17:57:09
【问题描述】:

我目前正在尝试制作一种算法,当所有节点都已被访问时,该算法可以为我提供图表的总成本,但我失败了,而且老实说没有想法。我的目标是使用 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)

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

【问题讨论】:

    标签: python algorithm graph shortest-path dijkstra


    【解决方案1】:

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

    相反,您需要累积“接受”的边的权重,即(隐式)从堆中弹出的边的权重,并提高该节点的距离。

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

    这是修改后的代码。这些变化伴随着 cmets:

    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
    

    【讨论】:

    • 成功了,非常感谢陌生人的详细回复和修复!
    猜你喜欢
    • 2014-05-18
    • 2013-08-11
    • 1970-01-01
    • 2018-03-09
    • 1970-01-01
    • 2011-06-27
    • 2017-01-08
    • 2021-02-28
    相关资源
    最近更新 更多