不平衡运输问题建模与求解(含 Python 程序)
示例1
一、问题描述
在如下运输问题中,存在三个产地(\(A_1, A_2, A_3\))和三个销地(\(B_1, B_2, B_3\)),已知单位运输成本、产地供应量和销地需求量:
| B₁ | B₂ | B₃ | 供应量 | |
|---|---|---|---|---|
| A₁ | 5 | 1 | 7 | 10 |
| A₂ | 6 | 4 | 6 | 80 |
| A₃ | 3 | 2 | 5 | 15 |
| 需求量 | 75 | 20 | 50 | 145\105 |
- 总供应量 = 10 + 80 + 15 = 105
- 总需求量 = 75 + 20 + 50 = 145
由于总需求量大于总供应量,该问题是一个不平衡运输问题。
二、平衡化处理:引入虚拟产地
为了将其转化为标准的平衡型运输问题,引入一个虚拟产地 \(A_4\),其供应量为:
可将该问题转化为平衡型运输问题,如下表所示:
| B₁ | B₂ | B₃ | 供应量 | |
|---|---|---|---|---|
| A₁ | 5 | 1 | 7 | 10 |
| A₂ | 6 | 4 | 6 | 80 |
| A₃ | 3 | 2 | 5 | 15 |
| A₄(虚拟) | 0 | 0 | 0 | 40 |
| 需求量 | 75 | 20 | 50 | 145\145 |
又因为该虚拟产地对各销地的单位惩罚成本如下:
- \(A_4 \rightarrow B_1\): 5
- \(A_4 \rightarrow B_2\): 3
- \(A_4 \rightarrow B_3\): 2
这样就对虚拟产地增加了惩罚成本\(5x_{41}+3x_{42}+2x_{43}\),参考该产地在目标函数中的成本\(0x_{41}+0x_{42}+0x_{43}\),可直接将惩罚成本修改为运输成本(比较后面数学模型),即更新后的运输成本表如下:
| B₁ | B₂ | B₃ | 供应量 | |
|---|---|---|---|---|
| A₁ | 5 | 1 | 7 | 10 |
| A₂ | 6 | 4 | 6 | 80 |
| A₃ | 3 | 2 | 5 | 15 |
| A₄(虚拟) | 5 | 3 | 2 | 40 |
| 需求量 | 75 | 20 | 50 | 145\145 |
三、数学模型
设 \(x_{ij}\) 表示从产地 \(A_i\) 运往销地 \(B_j\) 的数量,目标是最小化总运输成本:
目标函数:
约束条件:
- 供应约束:
- 需求约束:
- 非负性约束:
四、Python 求解代码
import numpy as np
from scipy.optimize import linprog
# 成本矩阵(按行展开)
costs = [
5, 1, 7, # A1
6, 4, 6, # A2
3, 2, 5, # A3
5, 3, 2 # A4 (虚拟)
]
# 供应量
supply = [10, 80, 15, 40] # A1, A2, A3, A4
# 需求量
demand = [75, 20, 50] # B1, B2, B3
# 构造约束矩阵 A_eq 和 b_eq
# 约束1:列方向,满足销地需求(每列之和等于需求)
A_eq = []
for j in range(3):
constraint = [0]*12
for i in range(4):
constraint[i*3 + j] = 1
A_eq.append(constraint)
b_eq = demand
# 约束2:行方向,不能超过供应量(每行之和等于供应)
A_ub = []
b_ub = []
for i in range(4):
constraint = [0]*12
for j in range(3):
constraint[i*3 + j] = 1
A_ub.append(constraint)
b_ub.append(supply[i])
# 非负界限
bounds = [(0, None)] * 12
# 求解
result = linprog(c=costs, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method='highs')
# 输出结果
if result.success:
print("最小总运输成本:", result.fun)
x = np.array(result.x).reshape((4,3))
print("运输方案:")
for i in range(4):
for j in range(3):
print(f"A{i+1} -> B{j+1} = {x[i][j]:.0f}")
else:
print("求解失败")
计算可得,最小总运输成本: 595.0,最优解见下表。
| B₁ | B₂ | B₃ | 供应量 | |
|---|---|---|---|---|
| A₁ | 0 | 10 | 0 | 10 |
| A₂ | 60 | 10 | 10 | 80 |
| A₃ | 15 | 0 | 0 | 15 |
| A₄(虚拟) | 0 | 0 | 40 | 40 |
| 需求量 | 75 | 20 | 50 | 145/145 |
五、结果解释
- 若虚拟产地 \(A_4\) 的运输量非零,表示有一部分需求无法由真实产地满足,即视为惩罚成本。
- 所得模型为标准平衡运输模型,可用于最小成本法、MODI法等进一步分析。
示例2
一、问题描述
在下表所示的不平衡运输问题中(方框中的数字为单位运价),若产地 \(i\) 有单位物资未运输出,则需要发生单位存储成本。已知:
- 单位存储成本为:
- \(A_1\): 5 元/单位
- \(A_2\): 4 元/单位
- \(A_3\): 3 元/单位
- 假设 \(A_2\) 的供货量必须全部运输出。
- 运价与供需如下表所示:
| 产地 | B1 | B2 | B3 | 供应量 |
|---|---|---|---|---|
| A1 | 1 | 2 | 1 | 20 |
| A2 | 0 | 4 | 5 | 40 |
| A3 | 2 | 3 | 3 | 20 |
| 需求 | 30 | 20 | 20 | 70\80 |
由于总供给量 \(20+40+20=80\),而总需求量为 \(30+20+20=70\),属于不平衡运输问题(供大于求)。
二、数学模型建立
设 \(x_{ij}\) 表示从产地 \(A_i\) 向销地 \(B_j\) 运送的数量,\(s_i\) 表示产地 \(A_i\) 的剩余库存。
目标函数(总运输成本 + 剩余存储成本)最小化:
其中 \(c_{ij}\) 是单位运价。
约束条件如下:
- 产地供给量约束:
- \(x_{11} + x_{12} + x_{13} + s_1 = 20\)
- \(x_{21} + x_{22} + x_{23} = 40\)(必须全部运出,\(s_2 = 0\))
- \(x_{31} + x_{32} + x_{33} + s_3 = 20\)
- 销地需求约束:
- \(x_{11} + x_{21} + x_{31} = 30\)
- \(x_{12} + x_{22} + x_{32} = 20\)
- \(x_{13} + x_{23} + x_{33} = 20\)
- 非负约束:
- 所有 \(x_{ij} \ge 0\),\(s_1, s_3 \ge 0\)
三、平衡运输问题转化
我们引入一个虚拟销地 B4,其需求为:
| B1 | B2 | B3 | B4(虚拟) | 供应量 | |
|---|---|---|---|---|---|
| A1 | 1 | 2 | 1 | 0 | 20 |
| A2 | 0 | 4 | 5 | 0 | 40 |
| A3 | 2 | 3 | 3 | 0 | 20 |
| 需求 | 30 | 20 | 20 | 10 | 80\80 |
鉴于还有存储成本的问题,且存储成本为\(5x_{14}+4x_{24}+3x_{34}\),所以需要在目标函数中添加该成本,而原来的成本表达为\(0x_{14}+0x_{24}+0x_{34}\),参看上面数学模型,所以可将存储成本看成为运价,更新后的运输成本表(单位运价表)为
| B1 | B2 | B3 | B4(虚拟) | 供应量 | |
|---|---|---|---|---|---|
| A1 | 1 | 2 | 1 | 5 | 20 |
| A2 | 0 | 4 | 5 | 4 | 40 |
| A3 | 2 | 3 | 3 | 3 | 20 |
| 需求 | 30 | 20 | 20 | 10 | 80\80 |
再考虑 \(A_2\) 的供货量必须全部运输出,即 \(A_2\) 不能向 \(B_4\) 供货,更新单位运价表如下:
| B1 | B2 | B3 | B4(虚拟) | 供应量 | |
|---|---|---|---|---|---|
| A1 | 1 | 2 | 1 | 5 | 20 |
| A2 | 0 | 4 | 5 | M | 40 |
| A3 | 2 | 3 | 3 | 3 | 20 |
| 需求 | 30 | 20 | 20 | 10 | 80\80 |
说明:\(M\) 表示一个极大值(如10000),用于限制 \(A_2 \to B4\) 的运输(因为题中要求 \(A_2\) 不能留库存)。
四、Python程序实现(使用 scipy.optimize.linprog)
import numpy as np
from scipy.optimize import linprog
# 成本矩阵展平为向量(A1到A3 -> B1到B4)
costs = [
1, 2, 1, 5, # A1 -> B1, B2, B3, B4
0, 4, 5, 1e6, # A2 -> B1, B2, B3, B4 (M=1e6, 禁止去B4)
2, 3, 3, 3 # A3 -> B1, B2, B3, B4
]
# 转换为矩阵形式:共 3x4 = 12 个变量
c = np.array(costs)
# 供给量
supply = [20, 40, 20]
# 需求量(含虚拟销地 B4)
demand = [30, 20, 20, 10]
# 构造不等式约束 A_ub x <= b_ub
# 每个产地的供给限制(按行)
A_ub = np.zeros((3, 12))
for i in range(3): # 每行是一个产地的4列相加 <= supply[i]
for j in range(4):
A_ub[i, i * 4 + j] = 1
b_ub = supply
# 构造等式约束 A_eq x = b_eq(每个销地的需求)
A_eq = np.zeros((4, 12))
for j in range(4): # 每列是一个销地
for i in range(3):
A_eq[j, i * 4 + j] = 1
b_eq = demand
# 变量边界(全部 >= 0)
bounds = [(0, None)] * 12
# 求解线性规划
res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method='highs')
# 输出结果
if res.success:
print("最小运输成本:", res.fun)
x = res.x.reshape(3, 4)
for i in range(3):
print(f"A{i+1} -> B1~B4: {x[i]}")
else:
print("求解失败")
计算可得,最小总运输成本: 120.0,最优解见下表。
| B1 | B2 | B3 | B4(虚拟) | 供应量 | |
|---|---|---|---|---|---|
| A1 | 0 | 0 | 20 | 0 | 20 |
| A2 | 30 | 10 | 0 | 0 | 40 |
| A3 | 0 | 10 | 0 | 10 | 20 |
| 需求 | 30 | 20 | 20 | 10 | 80/80 |
五、结果解释
- 最优解中,\(A\_2\) 所有物资都成功运输出去,未留库存,满足约束。
- \(A\_1\) 和 \(A\_3\) 的库存均为0,说明无需启用存储成本。
- 总运输成本为 120元。
- 虽然原问题为不平衡问题,但通过引入虚拟销地成功转化为平衡问题,从而利用标准运输问题求解法处理。

浙公网安备 33010602011771号