给定一个图,return从头到尾最多有k条边的最短路径

Given a graph, return the shortest path from start to end that has at most k edges

给定一个有向图,return从顶点开始到结束最多有 k 条边的最短路径

我的尝试

from heapq import heappush, heappop
def atMostK(n, edges, start, end, k):
    """
    :type edges: List[List[int]]
    :type start: int
    :type end: int
    :type k: int
    :rtype: int
    """
    graph = {}
    for (x, y, z) in edges:
        graph[x] = graph.get(x, []) + [(y, z)]
        
    table = {}
    for v in range(n):
        table[v] = (float("inf"), 0)  
    table[start] = (0, 0)
    
    
    stack = [(0,start)]
    visited = set()
    
    while(stack != []):
        node = heappop(stack)[1]
        w, cur_k = table[node]

        if(node in visited):
            continue
            
        visited.add(node)
        if(node in graph):
            for (v, weight) in graph[node]:
                
                
                cur_weight, amount = table[v]
                
                if(cur_weight > weight + w):
                    table[v] = (weight + w, amount + 1)
                    heappush(stack, (weight + w, v))
                    
    if(table[end][0] == float("inf")):
        return -1
    
    return table[end][0]
    

# fails on this

n = 3
edges = [[0,1,100],[1,2,100],[0,2,500]]
start = 0
end = 2
k = 1

print(atMostK(n, edges, start, end, k)) # 200, incorect result. Should be 500

# passes on this

n = 3
edges = [[0,1,100],[1,2,100],[0,2,500]]
start = 0
end = 2
k = 2

print(atMostK(n, edges, start, end, k)) # correct result

我尝试使用 dijkstra 算法,但是当我由于超过 k 边要求而需要回溯到之前访问过的节点时,我 运行 遇到了麻烦。

因此,例如从开始 = 0、结束 = 2 和 k = 1 使用此图

它将首先访问 0,然后转到 0->1 边缘,因为它比 0->2 边缘便宜,但为了转到 2,我需要另一个边缘,但我只允许 k=1,所以正确的结果应该是 500.

它适用于不需要我回溯到已经访问过的节点的图表,但除此之外它不会工作。我该怎么做?

使用 Bellman-Ford 的轻微修改,在最坏的情况下,您可以在 O(K*(|V| + |E|)) 时间内解决这个问题,对于一般情况有许多可能的优化。

运行 具有 k 次迭代的外循环;在 ith 迭代中,我们正在计算来自 start 的最小权重路径,最多有 i 条边。您确实需要从通常的 Bellman-Ford 进行一些额外的复制,以确保更新仅基于先前的循环迭代。

def atMostK(n, edges, start, end, k):
    """
    :type edges: List[List[int]]
    :type start: int
    :type end: int
    :type k: int
    :rtype: int
    """

    table = {}
    for v in range(n):
        table[v] = (float("inf"), 0)
    table[start] = (0, 0)

    for _ in range(min(k, n-1)):
        new_table = table.copy()
        for u, v, weight in edges:
            if table[u][0] + weight < new_table[v][0]:
                new_table[v] = (table[u][0] + weight, u)
        table = new_table

    if table[end][0] == float("inf"):
        return -1

    return table[end][0]

您也可以修改 Dijkstra 来执行此操作,但时间复杂度(和性能)可能更差且更难分析。您的最低优先级队列可以根据 (weight, num_edges, vertex) 进行排序,并进行检查以确保 num_edges 低于 k