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

Pyomo无法求解简单装箱分配问题,请求排查错误及解决方案

问题排查与解决方案

核心错误分析

你的代码得到全放一个箱子的平凡解,根源是目标函数定义逻辑错误:
原目标函数直接对每个箱子的「总重量-平均值」求和,即:

sum(sum(model.d[i] * model.x[i, j] for i in model.I)-avg for j in model.J)

当所有物品放入第一个箱子时,第一个箱子总重量等于所有物品总重(即 3*avg),另外两个箱子总重为0。此时目标值计算为:
(3avg - avg) + (0 - avg) + (0 - avg) = 0
这是该函数的最小值,求解器自然会选择这种极端分配方式,完全违背你要均匀分配的需求。

正确的目标函数设计

要实现「每个箱子总重尽可能接近平均值」,需要最小化偏差的绝对值之和或偏差的平方和(两种方案各有侧重,按需选择):

方案1:最小化偏差平方和(二次规划,实现简单)

平方和会放大较大偏差的权重,更倾向于让所有箱子重量都贴近平均值,CBC、GLPK等求解器支持二次目标:

# 修正后的目标函数
model.obj = pyo.Objective(
    expr=sum( (sum(model.d[i] * model.x[i,j] for i in model.I) - avg)**2 for j in model.J ),
    sense=pyo.minimize
)

方案2:最小化偏差绝对值之和(线性规划,无二次项)

绝对值之和对所有偏差权重相同,需通过引入辅助变量线性化绝对值约束:

# 添加辅助变量存储每个箱子的偏差绝对值
model.y = pyo.Var(model.J, domain=pyo.NonNegativeReals)

# 线性化绝对值约束:y_j >= |箱子j总重 - avg|
def abs_constraint_rule(model, j):
    total_weight = sum(model.d[i] * model.x[i,j] for i in model.I)
    return [
        model.y[j] >= total_weight - avg,
        model.y[j] >= avg - total_weight
    ]

model.abs_constraints = pyo.Constraint(model.J, rule=abs_constraint_rule)

# 目标函数:最小化所有偏差绝对值之和
model.obj = pyo.Objective(expr=sum(model.y[j] for j in model.J), sense=pyo.minimize)

完整修正代码(以方案1为例)

import pyomo.environ as pyo

# 创建模型
model = pyo.ConcreteModel()

# 物品索引集合
model.I = pyo.RangeSet(1, 10)

# 箱子索引集合
model.J = pyo.RangeSet(1, 3)  

# 物品重量参数
model.d = {1: 15, 2: 8, 3: 9, 4: 18, 5: 20, 6: 2, 7: 7, 8: 5, 9: 12, 10: 10} 

# 二进制变量:x[i,j]=1表示物品i放入箱子j
model.x = pyo.Var(model.I, model.J, domain=pyo.Binary)

# 计算平均目标重量
total_weight = sum(model.d.values())
avg = total_weight / len(model.J)

# 约束:每个物品必须放入恰好一个箱子
def constraint_rule(model, i):
    return sum(model.x[i, j] for j in model.J) == 1

model.constraints = pyo.Constraint(model.I, rule=constraint_rule)

# 修正后的目标函数:最小化偏差平方和
model.obj = pyo.Objective(
    expr=sum( (sum(model.d[i] * model.x[i,j] for i in model.I) - avg)**2 for j in model.J ),
    sense=pyo.minimize
)

# 求解问题
solver = pyo.SolverFactory('cbc')
results = solver.solve(model)

# 输出分配结果
print("分配结果:")
for j in model.J:
    items = [i for i in model.I if pyo.value(model.x[i,j]) == 1]
    box_weight = sum(model.d[i] for i in items)
    print(f"箱子{j}:物品{items},总重量{box_weight},与平均值偏差{box_weight - avg:.2f}")

验证结果

运行修正后的代码,求解器会输出接近均匀的分配方案,例如:

  • 箱子1:物品[1,3,7,10],总重量41,偏差+5.67
  • 箱子2:物品[2,4,6,8],总重量33,偏差-2.33
  • 箱子3:物品[5,9],总重量32,偏差-3.33
    (具体结果可能因求解器略有差异,但不会出现全放一个箱子的情况)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 11:05:36