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

Edmond最大分支算法Python实现方案咨询

Edmond最大分支算法Python实现指南

问题背景

我正在尝试实现Edmond最大分支算法的Python版本,该算法用于解决有向图的最大权重分支问题。

最大分支问题定义

给定有向图G=(V,E, w),其中w为权重函数,对于V中的根节点r,要求找到以r为根的分支G'=(V,E'),满足:

  • G'无环
  • 所有节点入度不超过1
  • 总权重最大

实现方案

方案1:调用成熟第三方库实现

最便捷的方式是直接使用networkx库的内置实现,networkx已经封装了经过工业界验证的Edmond最大分支算法,调用示例如下:

import networkx as nx

# 构造有向图
G = nx.DiGraph()
# 添加边,格式为(起点, 终点, 权重)
G.add_weighted_edges_from([
    (0, 1, 5),
    (0, 2, 3),
    (1, 2, 4),
    (2, 3, 2),
    (1, 3, 6)
])

# 计算以0为根的最大分支,算法参数adjustment为负表示求最大权重
max_branching = nx.maximum_branching(G, root=0)
# 输出总权重
print("最大分支总权重:", sum(d["weight"] for u, v, d in max_branching.edges(data=True)))
# 输出分支包含的边
print("分支边列表:", list(max_branching.edges()))

方案2:原生Python实现

如果你需要自行实现算法逻辑,参考核心实现代码如下:

def edmonds_max_branching(graph, root):
    # graph格式:{节点: {邻居: 权重}}
    n = len(graph)
    # 第一步:为每个非根节点选入度最大的边
    max_in = {}
    for u in graph:
        if u == root:
            continue
        max_weight = -float('inf')
        max_v = None
        for v in graph:
            if u in graph[v] and graph[v][u] > max_weight:
                max_weight = graph[v][u]
                max_v = v
        if max_v is None:
            raise ValueError("存在节点无法到达")
        max_in[u] = (max_v, max_weight)
    
    # 第二步:检测是否有环
    visited = set()
    cycle = None
    for u in max_in:
        if u in visited:
            continue
        path = []
        current = u
        while current is not None and current not in visited:
            visited.add(current)
            path.append(current)
            current = max_in[current][0] if current in max_in else None
        if current is not None and current in path:
            idx = path.index(current)
            cycle = path[idx:]
            break
    
    # 无环直接返回结果
    if cycle is None:
        edges = [(max_in[u][0], u, max_in[u][1]) for u in max_in]
        total_weight = sum(e[2] for e in edges)
        return total_weight, edges
    
    # 有环则收缩环为单个超级节点
    cycle_set = set(cycle)
    super_node = max(graph.keys()) + 1 if all(isinstance(k, int) for k in graph) else "super_" + str(hash(tuple(cycle)))
    new_graph = {}
    # 映射收缩前的边到收缩后的边,后续展开用
    edge_map = {}
    
    # 处理环外节点到环的边,选每个节点到环的最大权重边
    for v in graph:
        if v in cycle_set:
            continue
        new_graph[v] = {}
        max_to_cycle = -float('inf')
        best_u = None
        for u in graph[v]:
            if u in cycle_set:
                weight = graph[v][u] - max_in[u][1]
                if weight > max_to_cycle:
                    max_to_cycle = weight
                    best_u = u
        if best_u is not None:
            new_graph[v][super_node] = max_to_cycle
            edge_map[(v, super_node)] = (v, best_u)
        
        # 处理环到环外节点的边,选环里每个节点到环外的最大权重边
        for u in graph[v]:
            if u not in cycle_set and u != root:
                if super_node not in new_graph:
                    new_graph[super_node] = {}
                if u not in new_graph[super_node] or graph[v][u] > new_graph[super_node][u]:
                    new_graph[super_node][u] = graph[v][u]
                    edge_map[(super_node, u)] = (v, u)
    
    # 处理环外节点之间的边
    for v in graph:
        if v in cycle_set:
            continue
        for u in graph[v]:
            if u not in cycle_set and u != root and (v in new_graph) and (u not in new_graph[v]):
                new_graph[v][u] = graph[v][u]
                edge_map[(v, u)] = (v, u)
    
    # 递归计算收缩后的图的最大分支
    new_total, new_edges = edmonds_max_branching(new_graph, root if root not in cycle_set else super_node)
    
    # 展开超级节点,还原边
    total_weight = new_total + sum(max_in[u][1] for u in cycle)
    edges = []
    break_edge = None
    for e in new_edges:
        original_e = edge_map.get((e[0], e[1]), (e[0], e[1]))
        if original_e[1] in cycle_set:
            break_edge = original_e[1]
        edges.append(original_e)
    
    # 把环里除了break_edge对应的入边之外的其他边加回去
    for u in cycle:
        if u != break_edge:
            edges.append((max_in[u][0], u, max_in[u][1]))
    
    return total_weight, edges

# 调用示例
graph = {
    0: {1:5, 2:3},
    1: {2:4, 3:6},
    2: {3:2},
    3: {}
}
total, edges = edmonds_max_branching(graph, 0)
print("总权重:", total)
print("边列表:", edges)

补充说明

如果你已经参考相关方案完成了自己的实现,可以通过上述示例的测试用例验证实现的正确性,对比输出结果即可排查逻辑问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 21:06:02