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

如何在Gurobi求解器中最小化价格/权重比?附报错及代码

运输价格/权重比优化问题的Gurobi求解错误修复

问题概述

优化目标为降低产品运输的价格/权重比,涉及核心变量:

  • order:待配送订单的重量向量
  • w:每辆卡车的载重上限向量
  • p:每辆卡车的运输成本向量
  • n:单条配送路线的最大客户数量

报错分析

错误信息

TypeError                                 Traceback (most recent call last)
src/gurobipy/var.pxi in gurobipy.Var.__truediv__()

TypeError: float() argument must be a string or a number, not 'generator'

During handling of the above exception, another exception occurred:

GurobiError                               Traceback (most recent call last)
<ipython-input-5-18654dbac5a8> in <module>

---> 30 m.setObjective( gp.quicksum((z_n[i]/(gp.quicksum(x[i][j] *order[j]) for j in range(numItems))) for i in range(numTrucks)) , GRB.MINIMIZE)

src/gurobipy/gurobi.pxi in gurobipy.quicksum()

<ipython-input-5-18654dbac5a8> in <genexpr>(.0)
---> 30 m.setObjective( gp.quicksum((z_n[i]/(gp.quicksum(x[i][j] *order[j]) for j in range(numItems))) for i in range(numTrucks)) , GRB.MINIMIZE)

src/gurobipy/var.pxi in gurobipy.Var.__truediv__()

GurobiError: Divisor must be a constant

错误原因

  1. 语法错误:目标函数中gp.quicksum(x[i][j] *order[j] for j in range(numItems))被额外括号包裹,生成了生成器对象而非Gurobi表达式,触发TypeError。
  2. 核心约束限制:Gurobi不允许目标函数中出现变量除以变量的形式(属于非凸非线性规划),且要求除数必须为常数;同时原代码未处理卡车未使用时总重量为0的除以0风险。

解决方案

建模调整

  1. 添加二进制变量y[i],标记卡车i是否被使用。
  2. 修改成本变量z_n[i]的约束,仅当卡车被使用时(y[i]=1),z_n[i]等于对应运输成本p[i]。
  3. 添加约束:未使用的卡车不能装载任何订单;使用的卡车装载总重量需大于一个极小值(避免除以0)。
  4. 启用Gurobi的NonConvex参数,允许求解非线性目标函数。

修改后的代码

w = [650,1200,1200,1200,1200,1800,1800,1800,1800]
p = [250,330, 330, 330, 330, 400, 400, 400,400]
n = 7
order = [288,61,91,65,103,114,71,392,80,306,749,159,149,204,64,45,156,110,562,96,295,75,465,51,54,414,52,571,73,286,96,325,81,111,138,13,105,112,60,52,70,238,519,305,117,222,112,26,54,26,131,73,63,249,144,44,15,275,302]
numTrucks = len(w)
numItems = len(order)

import gurobipy as gp
from gurobipy import GRB

m = gp.Model('trucks optimization')

# 决策变量
x = m.addVars(numTrucks, numItems, vtype=gp.GRB.BINARY, name="x")  # x[i,j]表示卡车i是否装载订单j
y = m.addVars(numTrucks, vtype=gp.GRB.BINARY, name="y")  # y[i]表示是否使用卡车i
z_n = m.addVars(numTrucks, vtype=gp.GRB.CONTINUOUS, name="z_n")  # 卡车i的运输成本

# 约束条件
# 1. 每辆卡车装载的订单数不超过n
m.addConstrs(gp.quicksum(x[i,j] for j in range(numItems)) <= n * y[i] for i in range(numTrucks))
# 2. 每个订单必须被恰好一辆卡车装载
m.addConstrs(gp.quicksum(x[i,j] for i in range(numTrucks)) == 1 for j in range(numItems))
# 3. 每辆卡车的总装载重量不超过载重上限
m.addConstrs(gp.quicksum(x[i,j] * order[j] for j in range(numItems)) <= w[i] * y[i] for i in range(numTrucks))
# 4. 使用卡车时,运输成本等于p[i],否则为0
m.addConstrs(z_n[i] == p[i] * y[i] for i in range(numTrucks))
# 5. 使用卡车时,总装载重量至少为1(避免除以0)
m.addConstrs(gp.quicksum(x[i,j] * order[j] for j in range(numItems)) >= 1 * y[i] for i in range(numTrucks))

# 修正目标函数:去掉多余括号,处理非线性
# 目标是最小化各卡车(运输成本/运输重量)之和
truck_weight = {i: gp.quicksum(x[i,j] * order[j] for j in range(numItems)) for i in range(numTrucks)}
m.setObjective(gp.quicksum(z_n[i] / truck_weight[i] for i in range(numTrucks)), GRB.MINIMIZE)

# 启用非线性求解
m.setParam('NonConvex', 2)

m.optimize()

# 输出结果
if m.status == GRB.OPTIMAL:
    print("最优解:")
    for i in range(numTrucks):
        if y[i].x > 0.5:
            used_weight = sum(x[i,j].x * order[j] for j in range(numItems))
            print(f"卡车{i}:使用,成本{p[i]},装载重量{used_weight:.2f},价格/权重比{p[i]/used_weight:.4f}")
else:
    print("未找到最优解")

替代方案(线性分式规划)

若目标为全局价格/权重比最小(总运输成本/总运输重量),可通过Charnes-Cooper变换转化为线性规划:

w = [650,1200,1200,1200,1200,1800,1800,1800,1800]
p = [250,330, 330, 330, 330, 400, 400, 400,400]
n = 7
order = [288,61,91,65,103,114,71,392,80,306,749,159,149,204,64,45,156,110,562,96,295,75,465,51,54,414,52,571,73,286,96,325,81,111,138,13,105,112,60,52,70,238,519,305,117,222,112,26,54,26,131,73,63,249,144,44,15,275,302]
numTrucks = len(w)
numItems = len(order)

import gurobipy as gp
from gurobipy import GRB

m = gp.Model('trucks_global_ratio')

# 决策变量
x = m.addVars(numTrucks, numItems, vtype=gp.GRB.BINARY, name="x")
y = m.addVars(numTrucks, vtype=gp.GRB.BINARY, name="y")
t = m.addVar(vtype=gp.GRB.CONTINUOUS, name="t", lb=1e-6)  # 变换变量,t=1/总运输重量

# 约束条件
m.addConstrs(gp.quicksum(x[i,j] for j in range(numItems)) <= n * y[i] for i in range(numTrucks))
m.addConstrs(gp.quicksum(x[i,j] for i in range(numTrucks)) == 1 for j in range(numItems))
m.addConstrs(gp.quicksum(x[i,j] * order[j] for j in range(numItems)) <= w[i] * y[i] for i in range(numTrucks))

# Charnes-Cooper变换约束
total_weight = gp.quicksum(x[i,j] * order[j] for i in range(numTrucks) for j in range(numItems))
m.addConstr(total_weight * t == 1)
total_cost = gp.quicksum(p[i] * y[i] for i in range(numTrucks))

# 目标转化为最小化总成本*t(等价于总成本/总重量)
m.setObjective(total_cost * t, GRB.MINIMIZE)

m.optimize()

if m.status == GRB.OPTIMAL:
    total_weight_val = 1 / t.x
    total_cost_val = sum(p[i] * y[i].x for i in range(numTrucks))
    print(f"全局最优价格/权重比:{total_cost_val / total_weight_val:.4f}")
    print("卡车使用情况:")
    for i in range(numTrucks):
        if y[i].x > 0.5:
            used_weight = sum(x[i,j].x * order[j] for j in range(numItems))
            print(f"卡车{i}:装载重量{used_weight:.2f}")

内容的提问来源于stack exchange,提问作者Fernanda Almeida

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 07:48:27