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

如何使用Python将单地点线性规划(LP)模型扩展到多地点场景

多点位退货资源分配问题解决方案

你遇到的KeyError本质是多维度变量创建和访问时索引不匹配导致的,同时因为你的点位之间无耦合约束,有两种实现方案可选:

方案1:循环调用单点位模型(最简单,无额外调试成本)

因为每个点位的设备部署、成本计算完全独立,没有全局设备数量限制、跨点位运力调度等耦合约束,直接循环遍历所有点位运行你已有的单点位代码即可,完全不需要修改模型结构:

import gurobipy as gp
from gurobipy import GRB

# 输入参数:所有点位的退货量列表
locations = [120000, 850000, 300000] # 示例数据,替换成你的实际数据
result = []

for i, q in enumerate(locations):
    # 直接复用你原来的单点位代码
    m = gp.Model(f"point_{i}")
    BigM = 100
    cost_A = 20000
    cost_B = 13500
    cost_transport = 0.007
    cap_A = 400000
    cap_B = 500000
    
    x = m.addVar(lb=0, ub=3, vtype=GRB.INTEGER, name="A")
    y = m.addVar(lb=0, ub=3, vtype=GRB.INTEGER, name="B")
    z = m.addVar(lb=0, vtype=GRB.INTEGER, name="flow_1")
    a = m.addVar(vtype=GRB.BINARY, name="switch")
    
    m.setObjective(cost_A * x + cost_B * y + cost_transport * z, GRB.MINIMIZE)
    m.addConstr(z == q, "accept_demand")
    m.addConstr(z <= cap_A * x + cap_B * y, "capacity")
    m.addConstr(y <= x, "B_le_A")
    m.addConstr(x - y <= BigM * a, "switch_1")
    m.addConstr(y <= BigM * (1 - a), "switch_2")
    
    # 关闭日志输出避免刷屏
    m.setParam('OutputFlag', 0)
    m.optimize()
    
    # 保存结果
    result.append({
        "点位id": i,
        "退货量": q,
        "A设备数量": x.X,
        "B设备数量": y.X,
        "总成本": m.ObjVal
    })

# 打印所有结果
for res in result:
    print(res)

这个方案完全规避了多变量索引的问题,调试成本最低,运行效率也足够应对大多数点位规模场景。

方案2:整合式多点位MIP模型(适合后续要加全局约束的场景)

如果你后续需要加全局约束(比如总A设备不能超过10台、总成本上限等),可以把所有点位整合到一个模型里,正确的多变量创建和约束写法如下:

import gurobipy as gp
from gurobipy import GRB

# 输入参数
locations = [120000, 850000, 300000] # 示例数据
I = range(len(locations)) # 点位索引集合
BigM = 100
cost_A = 20000
cost_B = 13500
cost_transport = 0.007
cap_A = 400000
cap_B = 500000

# 创建模型
m = gp.Model("multi_point_return")

# 按点位索引创建变量,所有变量都是单维度i索引
x = m.addVars(I, lb=0, ub=3, vtype=GRB.INTEGER, name="A")
y = m.addVars(I, lb=0, ub=3, vtype=GRB.INTEGER, name="B")
z = m.addVars(I, lb=0, vtype=GRB.INTEGER, name="flow")
a = m.addVars(I, vtype=GRB.BINARY, name="switch")

# 目标函数:所有点位成本总和
m.setObjective(
    gp.quicksum(cost_A * x[i] + cost_B * y[i] + cost_transport * z[i] for i in I),
    GRB.MINIMIZE
)

# 批量加约束,每个点位一套约束
m.addConstrs((z[i] == locations[i] for i in I), "accept_demand")
m.addConstrs((z[i] <= cap_A * x[i] + cap_B * y[i] for i in I), "capacity")
m.addConstrs((y[i] <= x[i] for i in I), "B_le_A")
m.addConstrs((x[i] - y[i] <= BigM * a[i] for i in I), "switch_1")
m.addConstrs((y[i] <= BigM * (1 - a[i]) for i in I), "switch_2")

# 可选:添加全局约束示例,比如总A设备不超过5台
# m.addConstr(gp.quicksum(x[i] for i in I) <= 5, "total_A_limit")

# 求解
m.optimize()

# 输出结果
for i in I:
    print(f"点位{i}: A={x[i].X}, B={y[i].X}, 退货量={locations[i]}, 成本={cost_A * x[i].X + cost_B * y[i].X + cost_transport * locations[i]}")

KeyError规避说明

只要你严格按照定义的索引维度访问变量就不会报错:

  • 变量定义时用addVars(I, ...),I是单维度集合,访问时就用x[i],不要多写索引(比如x[i,j])也不要漏索引(比如直接用x参与计算)
  • 确保你访问时用的i都在I的范围内,不要用超过点位数量的索引值

非Gurobi实现方案

因为该问题每个点位的可选方案非常有限(A设备最多3台,B只能取0或等于A的数量),完全可以用穷举法计算所有可行方案的成本取最小值,不需要调用整数规划求解器:

def calc_best_plan(q):
    cost_A = 20000
    cost_B = 13500
    cost_transport = 0.007
    cap_A = 400000
    cap_B = 500000
    min_cost = float('inf')
    best_x = 0
    best_y = 0
    # 遍历所有可行的x(0-3)
    for x in range(0,4):
        # B只能取0或者x
        for y in [0, x]:
            # 校验容量是否满足
            if cap_A * x + cap_B * y >= q:
                total_cost = cost_A * x + cost_B * y + cost_transport * q
                if total_cost < min_cost:
                    min_cost = total_cost
                    best_x = x
                    best_y = y
    return best_x, best_y, min_cost

# 调用示例
locations = [120000, 850000, 300000]
for i, q in enumerate(locations):
    x,y,cost = calc_best_plan(q)
    print(f"点位{i}: A={x}, B={y}, 总成本={cost}")

该方案运行速度极快,不需要安装任何求解器依赖,适合小范围可行域的规划场景。

内容的提问来源于stack exchange,提问作者Bas van Rooij

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 19:27:02