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

使用Gurobi筛选25节点子图以最大化指定节点间边连通性的代码问题咨询

Gurobi筛选25节点子图以最大化指定节点间边连通性的代码问题咨询

首先得戳破你遇到的核心矛盾:你想把Gurobi的决策变量矩阵E直接丢给NetworkX的连通性函数当目标,但E是Gurobi的MVar类型(不是固定的Numpy数组),local_edge_connectivity根本没法处理它——更关键的是,Gurobi的目标函数必须是决策变量的显式数学表达式,不能是一个需要动态生成图结构的黑箱函数,这才是问题的根源。

那怎么绕开这个坑?我们可以用Menger定理来转译问题:两个节点间的边连通性,等于它们之间最多的边不相交路径数。所以我们可以把“最大化A和B的边连通性”,转换成“最大化k,使得存在k条从A到B的不相交路径,同时子图恰好包含25个节点(必须包含A、B)”。

下面是修正后的完整建模思路和代码:

建模思路拆解

  1. 保留节点选择变量F:F[node]为1表示选中该节点,0则不选;
  2. 新增边选择变量e:e[u,v]为1表示保留边(u,v),只有当u和v都被选中时,这条边才能保留;
  3. 新增流变量f:f[u,v]表示从u到v的流量,用来模拟k条不相交路径;
  4. 约束条件:
    • 选中节点数恰好25,且A、B必须被选中;
    • 边只能在两端节点都被选中时存在;
    • 流守恒:除A、B外,其他节点流入等于流出;A的总流出是k,B的总流入是k;
    • 每条边的流量不超过边是否被选中的变量(因为每条边最多走1条路径)。

修正后的代码实现

import networkx as nx
import gurobipy as grb

# 初始化原图
G = nx.hoffman_singleton_graph()
A = 5
B = 20
thresh_nodes = 25

# 整理节点和边的索引映射
nodes = list(G.nodes)
edges = list(G.edges)

# 初始化Gurobi模型
model = grb.Model("max_connectivity_subgraph")

# 1. 节点选择变量:F[node] = 1 表示选中该节点
F = model.addVars(nodes, vtype=grb.GRB.BINARY, name="node_select")
# 2. 边选择变量:e[u,v] = 1 表示保留该边
e = model.addVars(edges, vtype=grb.GRB.BINARY, name="edge_select")
# 3. 流变量:f[u,v] 表示边(u,v)上的路径流量
f = model.addVars(edges, vtype=grb.GRB.CONTINUOUS, name="flow")
# 4. k 是我们要最大化的边连通性(即最大不相交路径数)
k = model.addVar(vtype=grb.GRB.INTEGER, name="max_connectivity")

# --- 核心约束 ---
# 选中节点数恰好为25
model.addConstr(grb.quicksum(F[node] for node in nodes) == thresh_nodes, name="node_count_limit")
# 强制选中A和B
model.addConstr(F[A] == 1, name="must_keep_A")
model.addConstr(F[B] == 1, name="must_keep_B")

# 边只能在两端节点都被选中时保留
for u, v in edges:
    model.addConstr(e[u, v] <= F[u], name=f"edge_{u}_{v}_depends_on_u")
    model.addConstr(e[u, v] <= F[v], name=f"edge_{u}_{v}_depends_on_v")

# 流守恒约束:除A、B外,其他节点流入等于流出
for node in nodes:
    if node == A or node == B:
        continue
    inflow = grb.quicksum(f[v, node] for v in G.neighbors(node) if (v, node) in edges)
    outflow = grb.quicksum(f[node, v] for v in G.neighbors(node) if (node, v) in edges)
    model.addConstr(inflow == outflow, name=f"flow_conserv_{node}")

# A的总流出量等于k,B的总流入量等于k
model.addConstr(grb.quicksum(f[A, v] for v in G.neighbors(A)) == k, name="source_flow")
model.addConstr(grb.quicksum(f[v, B] for v in G.neighbors(B)) == k, name="sink_flow")

# 每条边的流量不能超过边是否被选中的变量(每条边最多走1条路径)
for u, v in edges:
    model.addConstr(f[u, v] <= e[u, v], name=f"flow_cap_{u}_{v}")

# 目标:最大化边连通性k
model.setObjective(k, grb.GRB.MAXIMIZE)

# 执行优化
model.optimize()

# --- 提取并验证结果 ---
if model.status == grb.GRB.OPTIMAL:
    # 筛选选中的节点和边
    selected_nodes = [node for node in nodes if F[node].X > 0.5]
    selected_edges = [(u, v) for u, v in edges if e[u, v].X > 0.5]
    # 构建子图
    subG = nx.Graph()
    subG.add_nodes_from(selected_nodes)
    subG.add_edges_from(selected_edges)
    # 验证连通性
    actual_connectivity = nx.local_edge_connectivity(subG, A, B)
    print(f"计算得到的最大边连通性: {int(k.X)}")
    print(f"实际验证的边连通性: {actual_connectivity}")
    print(f"选中的节点数量: {len(selected_nodes)}")
else:
    print("未找到可行的最优解")

为什么你的原代码跑不通?

你原代码里试图用local_edge_connectivity当目标函数,但Gurobi根本没法理解这个函数的内部逻辑——它需要的是能直接用决策变量拼出来的数学式子,而不是一个需要先构建图再计算的黑箱。通过把连通性转译成流的模型,我们把问题变成了Gurobi能处理的混合整数线性规划问题。

备注:内容来源于stack exchange,提问作者HJA24

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:33:02