获得最短的路径与额外的边缘与重量' w'?

时间:2017-05-03 21:07:59

标签: python shortest-path dijkstra graph-traversal

问题就像Dijkstra's Single Source Shourtest Path with an extra edge with weight of 'w'

您将获得一个无向加权图,它表示为邻接矩阵。找到图中起始节点和结束节点之间的最短路径。您可以在任何两个不直接相互连接的节点之间添加给定权重的最多一个边缘。

示例:

适用于start = 1finish = 4weight = 2

graph = [[0, 2, 0, 4, 0],
         [2, 0, 1, 0, 0],
         [0, 1, 0, 3, 0],
         [4, 0, 3, 0, 1],
         [0, 0, 0, 1, 0]]

输出应该是 shortestPathWithEdge(start, finish, weight, graph) == 3

我目前的解决方案使用Dijstra,但我根据有多少可能的边缘运行多次。我知道Dijstra,你可以获得所有节点的最短路径,但我似乎无法通过添加边缘连接来思考一种操作该数据的方法,而无需再次运行Dijstra算法。

图表可以是1000x1000。因此,使用大型矩阵,我的解决方案将太慢并且无法工作。

是否可以对Dijstra算法进行快速更新以处理其他边缘?

我的代码在下面,它可以工作但很慢。也许copy.copy也会导致它比它应该慢得多。

import copy

def getDistances(graph):
    ##### GET DISTANCES FROM GRAPH
    ##### PLACE IN DICTIONARY FORM
    distances = {}
    edges = set()

    for i, node in enumerate(graph):
        distances[i+1] = {}
        for j, distance in enumerate(node):
            ##### NO NEED TO GET DISTANCE TO ITSELF
            if i != j:
                distances[i+1][j+1] = distance
                if distance == 0 and (i+1,j+1) not in edges and (j+1,i+1) not in edges:
                    ##### ADD TO EDGES
                    edges.add((i+1,j+1))

    return distances, edges

def dijstra(visited,unvisited,currentNode,currentDistance,distances,finish):
    while True:
        for neighbor, distance in distances[currentNode].items():
            if distance == 0 or neighbor not in unvisited:
                continue

            newDistance = currentDistance + distance
            if unvisited[neighbor] == None or unvisited[neighbor] > newDistance:
                unvisited[neighbor] = newDistance

        visited[currentNode] = currentDistance
        del unvisited[currentNode]

        if not unvisited:
            break

        candidates = [node for node in unvisited.items() if node[1]]
        currentNode, currentDistance = sorted(candidates, key=lambda x: x[1])[0]

    ##### VISITED CONTAINS SHORTEST PATH TO ALL NODES
    return visited[finish]

def shortestPathWithEdge(start, finish, weight, graph):

    best = 10000000

    nodes = { i+1 for i in range(len(graph)) }
    distances, edges = getDistances(graph)

    #####IF NO EXTRA EDGE
    # visited = {}
    # unvisited = { node:None for node in nodes}
    # currentNode = start
    # currentDistance = 0
    # solution = dijstra(visited,unvisited,currentNode,currentDistance,distances,finish)

    #####WITH AN EXTRA EDGE
    solution = 10000000
    for node1, node2 in edges:
        _distances = copy.copy(distances)
        _distances[node1][node2] = weight
        visited = {}
        unvisited = {node: None for node in nodes}
        currentNode = start
        currentDistance = 0
        shortest2 = dijstra(visited, unvisited, currentNode, currentDistance, _distances, finish)

        solution = min(solution,shortest2)

    return solution


start = 1
finish = 4
weight = 2

graph = [[0, 2, 0, 4, 0],\
            [2, 0, 1, 0, 0], \
            [0, 1, 0, 3, 0], \
            [4, 0, 3, 0, 1],\
            [0, 0, 0, 1, 0]]

print("Answer:", shortestPathWithEdge(start, finish, weight, graph))

0 个答案:

没有答案