如何修正求有向图最多k条边最短路径的Dijkstra实现错误
原代码问题分析
你的实现是标准的无限制最短路径Dijkstra逻辑,不适用带k条边限制的场景,核心问题有4点:
- 全局
visited去重逻辑错误:常规Dijkstra中访问过的节点无需二次处理,但本场景中同一节点可以通过不同边数到达,边数更少的路径即使权重稍高,也可能在k限制下走通后续路径,全局去重会直接过滤这类有效路径。 - 边数计算逻辑错误:更新邻接节点边数时,错误取了邻接节点历史记录的边数加1,正确应该是当前节点的已用边数加1。
- 状态存储维度缺失:仅为每个节点保存一组「最小权重+对应边数」,会丢失「权重稍高但边数更少」的有效状态,这类状态往往是满足k限制的关键。
- 缺少边数超限判断:没有判断当前路径已用边数是否超过k,会生成不符合限制的路径结果。
修正后实现
from heapq import heappush, heappop def atMostK(n, edges, start, end, k): """ :type n: int :type edges: List[List[int]] :type start: int :type end: int :type k: int :rtype: int """ # 构建邻接表 graph = [[] for _ in range(n)] for x, y, weight in edges: graph[x].append((y, weight)) INF = float('inf') # dist[节点][已用边数] = 对应最小权重 dist = [[INF] * (k + 1) for _ in range(n)] dist[start][0] = 0 # 堆存储三元组:(当前总权重, 当前节点, 已使用边数) heap = [] heappush(heap, (0, start, 0)) while heap: cur_weight, u, used_edges = heappop(heap) # 剪枝:当前状态不是记录的最优值,直接跳过 if cur_weight > dist[u][used_edges]: continue # 已用边数达到上限,无法继续扩展 if used_edges >= k: continue # 扩展邻接节点 for v, w in graph[u]: new_weight = cur_weight + w new_used = used_edges + 1 # 新状态更优则更新 if new_weight < dist[v][new_used]: dist[v][new_used] = new_weight heappush(heap, (new_weight, v, new_used)) # 取所有不超过k条边到终点的最小权重 min_result = min(dist[end]) return min_result if min_result != INF else -1 # 测试用例1:k=1 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)) # 输出500,符合预期 # 测试用例2:k=2 k = 2 print(atMostK(n, edges, start, end, k)) # 输出200,符合预期
核心改动说明
- 移除全局
visited集合,改为在堆中携带「总权重、当前节点、已用边数」三个维度的状态,每条路径的状态独立计算。 - 新增二维
dist数组存储所有边数限制下的最小权重,避免有效状态丢失。 - 新增边数超限判断,扩展节点前先校验已用边数是否小于k,避免生成非法路径。
- 最终结果取所有不超过k条边到终点的路径的最小值,保证结果符合限制要求。
内容的提问来源于stack exchange,提问作者mol
相关产品推荐
相关产品推荐

