不平衡运输问题建模与求解(含 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\),其供应量为:

\[145 - 105 = 40 \]

可将该问题转化为平衡型运输问题,如下表所示:

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\) 的数量,目标是最小化总运输成本:

目标函数:

\[\min Z = \sum_{i=1}^{4} \sum_{j=1}^{3} c_{ij} x_{ij} \]

约束条件:

  • 供应约束

\[\sum_{j=1}^{3} x_{ij} \leq s_i \quad (i=1,2,3,4) \]

  • 需求约束

\[\sum_{i=1}^{4} x_{ij} = d_j \quad (j=1,2,3) \]

  • 非负性约束

\[x_{ij} \geq 0 \]


四、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\) 的剩余库存。

目标函数(总运输成本 + 剩余存储成本)最小化:

\[\min Z = \sum_{i=1}^{3} \sum_{j=1}^{3} c_{ij}x_{ij} + 5s_1 + 4s_2 + 3s_3 \]

其中 \(c_{ij}\) 是单位运价。

约束条件如下:

  1. 产地供给量约束:
    • \(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\)
  2. 销地需求约束:
    • \(x_{11} + x_{21} + x_{31} = 30\)
    • \(x_{12} + x_{22} + x_{32} = 20\)
    • \(x_{13} + x_{23} + x_{33} = 20\)
  3. 非负约束:
    • 所有 \(x_{ij} \ge 0\)\(s_1, s_3 \ge 0\)

三、平衡运输问题转化

我们引入一个虚拟销地 B4,其需求为:

\[B4\text{需求量} = 总供给 - 总需求 = 80 - 70 = 10 \]

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元
  • 虽然原问题为不平衡问题,但通过引入虚拟销地成功转化为平衡问题,从而利用标准运输问题求解法处理。

posted @ 2025-05-09 06:26  郝hai  阅读(153)  评论(0)    收藏  举报