本例产销平衡问题取自清华大学出版社《运筹学(第四版)》P94例1。问该公司应如何调运产品,在满足各销点的需要量的前提下,是总运输费最小。单位运价表和产销平衡表如下:
单位运价表
加工厂 \ 销地 | B 1 B_1 B1 | B 2 B_2 B2 | B 3 B_3 B3 | B 4 B_4 B4 |
---|---|---|---|---|
A 1 A_1 A1 | 3 | 11 | 3 | 10 |
A 2 A_2 A2 | 1 | 9 | 2 | 8 |
A 3 A_3 A3 | 7 | 4 | 10 | 5 |
产销平衡表
产地 \ 销地 | B 1 B_1 B1 | B 2 B_2 B2 | B 3 B_3 B3 | B 4 B_4 B4 | 产量 a i a_i ai |
---|---|---|---|---|---|
A 1 A_1 A1 | 7 | ||||
A 2 A_2 A2 | 4 | ||||
A 3 A_3 A3 | 9 | ||||
销量 b j b_j bj | 3 | 6 | 5 | 6 |
用 x i j x_{ij} xij 表示从 A i A_i Ai 到 B j B_j Bj 的运量, c i j c_{ij} cij 表示从 A i A_i Ai 到 B j B_j Bj 运输单位物资的运价。数学模型如下:
m i n z = ∑ i = 1 m ∑ j = 1 n c i j x i j min \ z = \sum_{i = 1}^m \sum_{j = 1}^n c_{ij}x_{ij} min z=i=1∑mj=1∑ncijxij
{ ∑ i = 1 m x i j = b j , j = 1 , 2 , ⋅ ⋅ ⋅ , n ∑ j = 1 m x i j = a i , i = 1 , 2 , ⋅ ⋅ ⋅ , n x i j ≥ 0 \left\{ \begin{array}{lcl} \sum_{i = 1}^mx_{ij} =b_j, j=1,2,···,n\\ \sum_{j = 1}^mx_{ij} =a_i, i=1,2,···,n\\ x_{ij}≥0 \end{array} \right. ⎩⎨⎧∑i=1mxij=bj,j=1,2,⋅⋅⋅,n∑j=1mxij=ai,i=1,2,⋅⋅⋅,nxij≥0
环境:python3.6;gurobi 9.0.3
首先导入第三方库gurobipy,在整段代码仅使用该库时,可用如下方式导入库中所有成员,这样可以简化代码,直接使用函数:
from gurobipy import *
m = Model("lp") # 建立模型, 无需使用 模块名.函数名/变量名 访问模块中成员
但应尽量避免使用from···import语句,因为这样可能导致名称冲突,且程序可读性差。本文使用如下方法导入库:
import gurobipy as gb
给出模型参数:
production, a = gb.multidict({'A1': 7, 'A2': 4, 'A3': 9}) # 产地
sales, b = gb.multidict({'B1': 3, 'B2': 6, 'B3': 5, 'B4': 6}) # 销地
route, cost = gb.multidict({
('A1', 'B1'): 3,
('A1', 'B2'): 11,
('A1', 'B3'): 3,
('A1', 'B4'): 10,
('A2', 'B1'): 1,
('A2', 'B2'): 9,
('A2', 'B3'): 2,
('A2', 'B4'): 8,
('A3', 'B1'): 7,
('A3', 'B2'): 4,
('A3', 'B3'): 10,
('A3', 'B4'): 5}) # 单位运价
构建模型:
m = gb.Model("lp4")
构建决策变量:
x = {}
for i, j in route:
x[i, j] = m.addVar(vtype=gb.GRB.INTEGER) # 构建决策变量x为整数
构建目标函数:
obj = gb.quicksum(x[i, j] * cost[i, j] for i, j in route) # 目标函数
m.setObjective(obj) # 默认最小化. 最大化则添加参数 gb.GRB.MAXIMIZE
添加约束条件并生成lp文档:
x = gb.tupledict(x)
m.addConstrs((x.sum("*", j) == b[j] for j in sales), name="con1") # 添加约束条件1
m.addConstrs((x.sum(i, "*") == a[i]for i in production), name="con2") # 添加约束条件2
m.write("lp4.lp")
求解并打印结果:
m.optimize() # 求解
for v in m.getVars():
print("%s %g" % (v.varName, v.x))
print("Obj: %g" % m.objVal)
求解结果:
'''Optimal solution found (tolerance 1.00e-04)
Best objective 8.500000000000e+01, best bound 8.500000000000e+01, gap 0.0000%
C0 0
C1 -0
C2 5
C3 2
C4 3
C5 -0
C6 0
C7 1
C8 -0
C9 6
C10 -0
C11 3
Obj: 85'''
得到最小运费是85元,运输方案如下表:
运输方案
产地 \ 销地 | B 1 B_1 B1 | B 2 B_2 B2 | B 3 B_3 B3 | B 4 B_4 B4 | 产量 |
---|---|---|---|---|---|
A 1 A_1 A1 | 5 | 2 | 7 | ||
A 2 A_2 A2 | 3 | 1 | 4 | ||
A 3 A_3 A3 | 6 | 3 | 9 | ||
销量 | 3 | 6 | 5 | 6 |
# -*- coding: utf-8 -*-
"""
Created on Oct
@author: AsmallFROG
"""
import gurobipy as gb
production, a = gb.multidict({'A1': 7, 'A2': 4, 'A3': 9}) # 产地
sales, b = gb.multidict({'B1': 3, 'B2': 6, 'B3': 5, 'B4': 6}) # 销地
route, cost = gb.multidict({
('A1', 'B1'): 3,
('A1', 'B2'): 11,
('A1', 'B3'): 3,
('A1', 'B4'): 10,
('A2', 'B1'): 1,
('A2', 'B2'): 9,
('A2', 'B3'): 2,
('A2', 'B4'): 8,
('A3', 'B1'): 7,
('A3', 'B2'): 4,
('A3', 'B3'): 10,
('A3', 'B4'): 5}) # 单位运价
m = gb.Model("lp4") # 构建模型
x = {}
for i, j in route:
x[i, j] = m.addVar(vtype=gb.GRB.INTEGER) # 构建决策变量x为整数
obj = gb.quicksum(x[i, j] * cost[i, j] for i, j in route) # 目标函数
m.setObjective(obj) # 默认最小化. 最大化则添加参数 gb.GRB.MAXIMIZE
x = gb.tupledict(x)
m.addConstrs((x.sum("*", j) == b[j] for j in sales), name="con1") # 添加约束条件1
m.addConstrs((x.sum(i, "*") == a[i]for i in production), name="con2") # 添加约束条件2
m.write("lp4.lp")
m.optimize() # 求解
for v in m.getVars():
print("%s %g" % (v.varName, v.x))
print("Obj: %g" % m.objVal)