You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带权有环图最短路径求解:递归函数适配问题咨询

解决带权有环图的最短路径问题

嘿,我来帮你搞定这个问题!你现在的递归函数只能处理无环图的最短路径,而带权有环图的核心挑战是避免无限递归遍历环,同时还要能识别出比之前更短的路径(哪怕需要经过某个节点多次,但正权环的话其实不会有更短路径,不过还是要做剪枝处理)。

先看你给出的示例图,这是个正权有环图(比如E→B→C→E的总权重是9,走这个环只会增加总长度),所以我们可以基于你的递归思路,加入剪枝逻辑和最短距离追踪来改造函数。

问题分析

你原函数的visited列表会限制对节点的重复访问,但在有环图中,可能存在不同路径到同一个节点且权重更小的情况——比如假设从A到B有两条路径:A→B(权重5)和A→E→B(权重7+3=10),显然前者更短,但如果先遍历了A→E→B,之后再遇到A→B时,我们需要允许更新最短距离。同时,正权环的存在会导致无限递归,所以必须在递归中判断当前路径是否已经没有优化空间,及时终止。

改造后的递归实现

我给你写了一个基于深度优先搜索(DFS)的递归实现,加入了剪枝和状态维护:

import sys

class ShortestPathSolver:
    def __init__(self, graph):
        self.graph = graph
        # 记录从起点到每个节点的最短距离,初始为无穷大
        self.min_distances = {node: float('inf') for node in graph}
        # 记录到每个节点的最短路径
        self.shortest_paths = {}

    def find_shortest_route(self, start, end):
        # 初始化起点的距离和路径
        self.min_distances[start] = 0
        self.shortest_paths[start] = [start]
        # 启动递归搜索
        self._dfs_recursive(start, end, 0, [start])
        # 返回结果:如果终点不可达则返回None和无穷大
        return self.shortest_paths.get(end, None), self.min_distances.get(end, float('inf'))

    def _dfs_recursive(self, current_node, end_node, current_weight, current_path):
        # 到达终点,检查是否是更短的路径
        if current_node == end_node:
            if current_weight < self.min_distances[end_node]:
                self.min_distances[end_node] = current_weight
                self.shortest_paths[end_node] = current_path.copy()
            return

        # 遍历当前节点的所有邻居
        for neighbor, edge_weight in self.graph[current_node].items():
            new_total_weight = current_weight + edge_weight
            # 剪枝:如果这条路径到邻居的权重已经不小于已知的最短距离,直接跳过
            if new_total_weight >= self.min_distances[neighbor]:
                continue
            # 更新邻居的最短距离和路径
            self.min_distances[neighbor] = new_total_weight
            self.shortest_paths[neighbor] = current_path + [neighbor]
            # 递归探索邻居节点
            current_path.append(neighbor)
            self._dfs_recursive(neighbor, end_node, new_total_weight, current_path)
            # 回溯:移除当前邻居,恢复路径状态
            current_path.pop()

# 测试你的示例图
if __name__ == "__main__":
    graph = {
        'A': {'B': 5, 'D': 5, 'E': 7},
        'B': {'C': 4},
        'C': {'D': 8, 'E': 2},
        'D': {'C': 8, 'E': 6},
        'E': {'B': 3}
    }
    solver = ShortestPathSolver(graph)
    path, weight = solver.find_shortest_route('A', 'E')
    print(f"最短路径: {path}")
    print(f"总权重: {weight}")

关键改进点

  • 状态维护:用类的成员变量min_distances和shortest_paths来追踪全局的最短距离和路径,避免递归时反复传递大量参数。
  • 剪枝逻辑:当当前路径到邻居的权重已经大于等于已知的最短距离时,直接跳过这个分支,既避免了无效递归,也防止了正权环的无限遍历。
  • 回溯操作:递归前后的append和pop保证了当前路径的状态正确,不会混淆不同分支的路径。

额外说明

如果你的图中存在负权环(总权重为负的环),那最短路径是不存在的(可以无限绕环降低总权重),这时候需要用Bellman-Ford算法来检测负权环。但你的示例图都是正权边,上面的实现完全适用。

内容的提问来源于stack exchange,提问作者Shadid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:40:37