如何解决Gurobi报错‘Divisor must be a constant’并正确实现目标函数?
问题分析与解决方案
1. 错误根源:变量做除数违反Gurobi规则
Gurobi作为线性/整数规划求解器,绝对不允许把决策变量(比如你的x[i,j])当作除数——这就是你看到Divisor must be a constant报错的直接原因。另外你目标函数里的if x!=0条件判断,也没法直接在Gurobi的线性表达式里实现,这种离散逻辑需要特殊处理,但其实你的需求根本不需要这么做。
2. 目标函数的等价线性转换
从你的代码逻辑推断,你应该是想最大化「总运输成本节约量」:对每一笔从工厂到客户的运输,计算D - d[i,j](单位运输量的节约值),再乘以运输量x[i,j],最后求和。
我们可以通过数学推导把你原本的目标逻辑转化为完全线性的形式:
假设你原本想对每个工厂i计算D - (Σ(d[i,j]x[i,j]) / Σx[i,j]),再乘以该工厂的总运输量Σx[i,j],最后把所有工厂的结果加起来。展开后就是:
Σ[ D*Σx[i,j] - Σ(d[i,j]x[i,j]) ] = ΣΣ( (D - d[i,j]) * x[i,j] )
这个线性表达式完全符合Gurobi的要求,不需要任何除法操作。
3. 代码修改细节
(1)修复目标函数
把原来的目标函数替换成下面的线性版本:
model.setObjective(quicksum((D - d[i,j]) * x[i,j] for i in P for j in W), GRB.MAXIMIZE)
(2)删除冗余约束
你写的这个约束完全是多余的,删掉它能减少不必要的计算开销:
# 这个约束可以直接删除,因为d[i,j]最大是5,D=100,5*x[i,j] <=100*x[i,j]恒成立 for i in P: for j in W: model.addConstr(d[i,j]*x[i,j],"<=",D*x[i,j])
(3)修正变量名冲突(可选但推荐)
你用import pandas as p,同时又用P,p=multidict(...),这会导致p被覆盖。建议把pandas的导入改成import pandas as pd,避免变量名冲突。
(4)修正输出的工厂/客户顺序
你的输出语句里工厂和客户的顺序搞反了,而且要获取变量的最优值需要用.X属性:
print("sending quantity %10.2f from factory %3s to customer %3s" %(x[i,j].X, i, j))
完整修改后的代码
from gurobipy import * import pandas as pd # 修正变量名冲突 import numpy as np d={ (1,1):2,(1,2):3,(1,3):3,(1,4):5, (2,1):2,(2,2):3,(2,3):3,(2,4):5, (3,1):2,(3,2):3,(3,3):3,(3,4):5, (4,1):2,(4,2):3,(4,3):3,(4,4):5, (5,1):2,(5,2):3,(5,3):3,(5,4):5, } P,p_cap=multidict({1:1,2:1,3:2,4:2,5:2}) # 改名p为p_cap,避免冲突 W,w_demand=multidict({1:2,2:2,3:2,4:2}) # 改名w为w_demand,更清晰 D=100 total_p=sum([i for i in p_cap.values()]) total_w=sum([j for j in w_demand.values()]) if total_w/total_p<1: R= total_w/total_p else : R=1 print(R) model=Model("keibi optimizer") x={} for i in P: for j in W: x[i,j]=model.addVar(vtype="C",name="x(%s,%s)"%(i,j)) model.update() # 需求约束 for j in W: model.addConstr(quicksum(x[i,j] for i in P) == w_demand[j],name='Demand(%s)' %j) # 产能约束 for i in P: model.addConstr(quicksum(x[i,j] for j in W) <= p_cap[i],name='Capacity(%s)' %i) # 修正后的线性目标函数 model.setObjective(quicksum((D - d[i,j]) * x[i,j] for i in P for j in W), GRB.MAXIMIZE) model.optimize() print("Optimal value:", model.ObjVal/(total_p*D)) for(i,j) in x: # 用.X获取最优值,修正工厂和客户的顺序 print("sending quantity %10.2f from factory %3s to customer %3s" %(x[i,j].X, i, j))
验证说明
修改后的代码:
- 完全符合Gurobi的线性规划要求,不会再出现除数错误
- 目标函数等价于你原本想实现的逻辑(最大化总节约值)
- 修复了变量名冲突和输出顺序的问题
- 删除了冗余约束,提升求解效率
内容的提问来源于stack exchange,提问作者炎天下修羅
相关产品推荐
相关产品推荐

