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

无向加权连通图指定起点全节点遍历的最小/最大路径代价求解咨询

嘿,这个问题本质上是哈密顿路径的权重极值求解,属于旅行商问题(TSP)的简化版(不需要回到起点)。我给你拆解下具体的实现逻辑,分不同场景来聊:

核心问题定位

我们要找的是从指定起始节点出发,经过图中所有节点恰好一次的路径里,总权重最小和最大的那两个的代价。因为是无向加权连通图,所以任意两个节点之间都有路径可达,保证存在这样的哈密顿路径。

实现逻辑拆解

一、暴力回溯法(适合小规模图)

如果你的图节点数不多(比如n≤10),暴力枚举所有可能的路径完全可行,逻辑也最直观。

  • 核心思路:从起始节点出发,递归遍历所有没访问过的节点,记录当前路径的总代价;当所有节点都被访问时,更新我们记录的最小、最大代价。
  • 具体步骤:
    • 维护一个访问状态数组,初始时只有起始节点标记为已访问。
    • 写一个递归函数,参数包括当前所在节点、已访问的节点数量、当前路径的总代价。
    • 当已访问节点数等于图的总节点数时,把当前代价和已记录的最小/最大代价对比,更新对应的值。
    • 遍历当前节点的所有邻接节点,如果邻接节点没被访问,就标记为已访问,递归调用函数,之后再回溯(取消标记),尝试其他路径。
  • 伪代码示例(Python风格):
def find_min_max_path(graph, start):
    n = len(graph)
    visited = [False] * n
    visited[start] = True
    min_total = float('inf')
    max_total = float('-inf')

    def backtrack(current_node, visited_count, current_cost):
        nonlocal min_total, max_total
        # 所有节点都访问完了,更新极值
        if visited_count == n:
            if current_cost < min_total:
                min_total = current_cost
            if current_cost > max_total:
                max_total = current_cost
            return
        # 遍历当前节点的所有邻接点
        for neighbor in range(n):
            if not visited[neighbor] and graph[current_node][neighbor] != 0:
                visited[neighbor] = True
                backtrack(neighbor, visited_count + 1, current_cost + graph[current_node][neighbor])
                visited[neighbor] = False  # 回溯,尝试其他分支

    backtrack(start, 1, 0)
    return min_total, max_total
  • 优缺点:逻辑简单好理解,但时间复杂度是O(n!),节点数一多(比如n=12)就会慢到离谱,只适合小图。

二、动态规划法(适合中等规模图)

针对TSP问题的经典优化方法,用状态压缩来记录访问过的节点集合,效率比暴力法高很多。

  • 核心思路:用dp[mask][u]来表示「已经访问过的节点集合是mask(mask是二进制数,第i位为1代表节点i已访问),当前处于节点u」时的最小/最大代价。
  • 具体步骤:
    • 初始化:对于起始节点s,dp[1<<s][s] = 0(只访问了s节点,代价为0);其他状态的最小代价初始化为无穷大,最大代价初始化为负无穷。
    • 遍历所有可能的mask状态,对于每个mask,再遍历所有已被访问的节点u,接着遍历所有未访问的节点v:如果u和v之间有边,就更新dp[mask | (1<<v)][v]的值:
      • 最小代价:取「当前状态的代价」和「从u走到v后的代价」里的较小值
      • 最大代价:取「当前状态的代价」和「从u走到v后的代价」里的较大值
    • 最终结果:当所有节点都被访问时(mask = (1<<n)-1),遍历所有节点u,dp[(1<<n)-1][u]中的最小值就是最小路径代价,最大值就是最大路径代价(因为不需要回到起点,最后停在任何节点都可以)。
  • 伪代码示例:
def tsp_dp_solution(graph, start):
    n = len(graph)
    # 初始化DP表:min_dp存最小代价,max_dp存最大代价
    min_dp = [[float('inf')] * n for _ in range(1 << n)]
    max_dp = [[float('-inf')] * n for _ in range(1 << n)]
    min_dp[1 << start][start] = 0
    max_dp[1 << start][start] = 0

    # 遍历所有可能的访问状态mask
    for mask in range(1 << n):
        for u in range(n):
            if not (mask & (1 << u)):
                continue  # u不在当前访问集合里,跳过
            # 遍历所有未访问的节点v
            for v in range(n):
                if mask & (1 << v):
                    continue  # v已访问,跳过
                if graph[u][v] == 0:
                    continue  # u和v之间没有边,跳过
                # 更新最小代价
                if min_dp[mask][u] + graph[u][v] < min_dp[mask | (1 << v)][v]:
                    min_dp[mask | (1 << v)][v] = min_dp[mask][u] + graph[u][v]
                # 更新最大代价
                if max_dp[mask][u] + graph[u][v] > max_dp[mask | (1 << v)][v]:
                    max_dp[mask | (1 << v)][v] = max_dp[mask][u] + graph[u][v]

    # 所有节点都访问过的状态是(1<<n)-1,遍历所有节点取极值
    final_mask = (1 << n) - 1
    min_cost = min(min_dp[final_mask][u] for u in range(n))
    max_cost = max(max_dp[final_mask][u] for u in range(n))
    return min_cost, max_cost
  • 优缺点:时间复杂度是O(n²2ⁿ),空间复杂度O(n2ⁿ),能处理n≤16左右的图,比暴力法高效太多。

三、大规模图的近似算法

如果你的图节点数超过20,连DP法都会因为内存和时间问题吃不消,这时候可以用近似算法来快速得到接近最优的结果:

  • 最小路径:可以用贪心策略,每次从当前节点选择到未访问节点的最小权重边走;或者先生成图的最小生成树,然后遍历生成树得到近似路径(比如深度优先遍历)。
  • 最大路径:类似贪心,每次选当前节点到未访问节点的最大权重边;或者生成最大生成树后遍历。
  • 注意:近似算法不能保证得到绝对最优解,但能在短时间内拿到可用的结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:53:01