转运运输问题——Python实现(二)
转运运输问题在供应链管理中起着至关重要的作用。供应链是一个涉及从原材料采购到产品交付的复杂网络,其中运输是连接不同环节的关键环节。转运运输问题涉及如何高效地将物品从一个地点转移到另一个地点,以满足客户需求并最小化成本。在供应链背景下,转运运输问题需要考虑多个因素,如货物类型、数量、运输距离、交货时间、货车容量等。优化转运运输可以帮助企业降低成本、提高交付效率,从而增强竞争力。这可以通过合理的运输路线规划、货车装载优化、运输调度等方式实现。现代技术的应用使得解决转运运输问题变得更加高效。例如,使用智能物流系统和物流管理软件可以实时跟踪货物位置、优化运输路线和调度,减少空载率和运输时间。另外,物联网技术可以实现对货物和运输工具的远程监控,提供数据支持决策。
 
一、转运问题
除了常规的运输路线,运输是还可能包括发点到发点、收点到收点,甚至收点到发点的运输,这类运输问题考虑复杂的运输网络,称为转运问题。转运问题是指除了供给点和需求点之外运输时的中间节点,并且可以转化为一个运输问题。
供给点(supply point)是指可以发货但不能收货的点
需求点(demand point)是指可以收货但不能发货的点
转运点(transshipment point)是同时可以收货和发货的点

二、转运问题的数学模型
设有\(m\)个地点(称为产地或发地)\(A_i,i=1,2,...,m\)的某种物资调至\(n\)个地点(称为销地或收地)\(B_{m+j},j=1,2,...,n\),各个产地需要调出的物资量分别为\(a_i\)单位,各个销地需要调进的物资量分别为\(b_j\)单位,且$$ \sum_{i=1}^{m}a_i = \sum_{j=1}^{n}b_j=Q$$
现假设各个产地和销地之间可以转运,将产地和销地重新编号,就变成共有\(m+n\)个产地和\(m+n\)销地的运输问题,已知每个产地\(i\)到每个销地\(j\)的物资单位调运价格为\(c_{ij}\);各个运输节点的单位转运费\(c_k,k=1,2,...,m+n\);各个运输节点的转运量为\(t_k,k=1,2,...,m+n\),现问如何安排调运,才能使总运费最小。
| 序号 | 1 | ... | \(m\) | \(m+1\) | ... | \(m+n\) | 发送量 | |
|---|---|---|---|---|---|---|---|---|
| 产地 | 1 | ... | \(x_{1m}\) | \(x_{1,m+1}\) | ... | \(x_{1,m+n}\) | \(a_1+t_1\) | |
| ... | ... | ... | ... | ... | ... | ... | ||
| \(m\) | \(x_{m1}\) | ... | \(x_{m,m+1}\) | ... | \(x_{m,m+n}\) | \(a_m+t_m\) | ||
| 销地 | \(m+1\) | \(x_{m+1,1}\) | ... | \(x_{m+1,m}\) | ... | \(x_{m+1,m+n}\) | \(t_{m+1}\) | |
| ... | ... | ... | ... | ... | ... | ... | ||
| \(m+n\) | \(x_{m+n,1}\) | ... | \(x_{m+n,m}\) | \(x_{m+n,m+1}\) | ... | \(t_{m+n}\) | ||
| 接收量 | \(t_1\) | ... | \(t_m\) | \(b_1+t_{m+1}\) | ... | \(b_n+t_{m+n}\) | 
根据上面变量表,可建立有转运的运输问题的数学模型
做变换,令\(x_{ii}=Q-t_i\),\(c_{ii}=-c_i\),代入上面模型,得
| 序号 | 1 | ... | \(m\) | \(m+1\) | ... | \(m+n\) | 发送量 | |
|---|---|---|---|---|---|---|---|---|
| 产地 | 1 | \(-c_1\) | ... | \(x_{1m}\) | \(x_{1,m+1}\) | ... | \(x_{1,m+n}\) | \(Q+a_1\) | 
| ... | ... | \(-c_i\) | ... | ... | ... | ... | ... | |
| \(m\) | \(x_{m1}\) | ... | \(-c_m\) | \(x_{m,m+1}\) | ... | \(x_{m,m+n}\) | \(Q+a_m\) | |
| 销地 | \(m+1\) | \(x_{m+1,1}\) | ... | \(x_{m+1,m}\) | \(-c_{m+1}\) | ... | \(x_{m+1,m+n}\) | \(Q\) | 
| ... | ... | ... | ... | ... | \(-c_{m+j}\) | ... | ... | |
| \(m+n\) | \(x_{m+n,1}\) | ... | \(x_{m+n,m}\) | \(x_{m+n,m+1}\) | ... | \(-c_{m+n}\) | \(Q\) | |
| 接收量 | \(Q\) | ... | \(Q\) | \(Q+b_1\) | ... | \(Q+b_n\) | 
三、转运问题示例
3.1 示例1

建立转运矩阵,注意单位转运费为零
| A | B | C | D | E | 供应量 | |
|---|---|---|---|---|---|---|
| A | 0 | 3 | 12 | 10 | 4 | 47 | 
| B | 3 | 0 | 6 | 10 | 5 | 34 | 
| C | 12 | 6 | 0 | 2 | 3 | 27 | 
| D | 10 | 10 | 2 | 0 | 6 | 27 | 
| E | 4 | 5 | 2 | 6 | 0 | 27 | 
| 需求量 | 27 | 27 | 36 | 36 | 36 | 
该问题Python求解
import pulp
import numpy as np
from pprint import pprint
def transport_problem(costs, x_max, y_max):
    row = len(costs)
    col = len(costs[0])
    prob = pulp.LpProblem('Transportation Problem', sense=pulp.LpMinimize)  # Changed to minimize
    var = [[pulp.LpVariable(f'x{i}{j}', lowBound=0, cat=pulp.LpInteger)
            for j in range(col)] for i in range(row)]
    flatten = lambda x: [y for l in x for y in flatten(l)] if type(x) is list else [x]
    prob += pulp.lpDot(flatten(var), costs.flatten())  # Objective function
    for i in range(row):
        prob += (pulp.lpSum(var[i])) == x_max[i]  # Modified constraint: Equality instead of inequality
    for j in range(col):
        prob += (pulp.lpSum(var[i][j] for i in range(row))) == y_max[j]  # Modified constraint: Equality instead of inequality
    prob.solve()
    return {'objective': pulp.value(prob.objective), 'var': [[pulp.value(var[i][j]) for j in range(col)] for
                                                               i in range(row)]}
if __name__ == '__main__':
    costs = np.array([[0, 3, 12, 10, 4],
                      [3, 0, 6, 10, 5],
                      [12, 6, 0, 2, 3],
                      [10, 10, 2, 0, 6],
                      [4, 5, 2, 6, 0]])
    max_plant = [47, 34, 27, 27, 27]
    max_cultivation = [27, 27, 36, 36, 36]
    res = transport_problem(costs, max_plant, max_cultivation)
    print(f'最小值为{res["objective"]}')
    print('各变量的取值为: ')
    pprint(res['var'])
最小值为162.0
各变量的取值为: 
[[27.0, 0.0, 0.0, 0.0, 20.0],
 [0.0, 27.0, 7.0, 0.0, 0.0],
 [0.0, 0.0, 18.0, 9.0, 0.0],
 [0.0, 0.0, 0.0, 27.0, 0.0],
 [0.0, 0.0, 11.0, 0.0, 16.0]]
3.2 示例2

建立转运矩阵
| 发送地 | 产 | 地 | 转运 | 销 | 地 | 发送量 | |
|---|---|---|---|---|---|---|---|
| 接收地 | 1 | 2 | 3 | 4 | 5 | 发送量 | |
| 产 | 1 | -4 | 5 | 3 | 2 | M | 60 | 
| 地 | 2 | 5 | -1 | 2 | M | 4 | 90 | 
| 转运 | 3 | 3 | 2 | -3 | 5 | 5 | 50 | 
| 销 | 4 | 2 | M | 5 | -3 | 6 | 50 | 
| 地 | 5 | M | 4 | 5 | 6 | -5 | 50 | 
| 接收量 | 接收量 | 50 | 50 | 50 | 80 | 70 | 300\300 | 
求出调运方案
| 发送地 | 产 | 地 | 转运 | 销 | 地 | ||
|---|---|---|---|---|---|---|---|
| 接收地 | 1 | 2 | 3 | 4 | 5 | 发送量 | |
| 产 | 1 | -4(50) | 5 | 3 | 2 (10) | M | 60 | 
| 地 | 2 | 5 | -1(50) | 2(20) | M | 4 (20) | 90 | 
| 转运 | 3 | 3 | 2 | -3(30) | 5 (20) | 5 | 50 | 
| 销 | 4 | 2 | M | 5 | -3 (50) | 6 | 50 | 
| 地 | 5 | M | 4 | 5 | 6 | -5(50) | 50 | 
| 接收量 | 50 | 50 | 50 | 80 | 70 | 300\300 | 
\(Z=c_{14}x_{14}+c_{23}x_{23}+c_{25}x_{25}+c_{34}x_{34}=2\times 10+2\times 20+4\times 20+5\times 20=240\)
3.3 示例3(前例3)
例3:某供应链企业经销汽车配件A,下设2个分别位于沈阳和郑州的加工厂。该公司每月需要把各产地生产的产品分别运往北京、上海、广州3个销售点。运输过程中,允许经天津、武汉2个中转站进行转运。公司在租用运输车辆时,租赁公司给出如下的单位运价表。天津和武汉两个中转地的运输能力约束为500,400,问在考虑到产销地之间非直接运输的各种可能方案的情况下,如何将2个加工厂每月生产的产品运往销售地,使总的运费最低?
| 天津\(T_1\) | 武汉\(T_2\) | 北京\(B_1\) | 上海\(B_2\) | 广州\(B_3\) | 供应量 | |
|---|---|---|---|---|---|---|
| 沈阳\(A_1\) | 210 | 470 | — | — | — | 500 | 
| 郑州\(A_2\) | 230 | 160 | — | — | — | 300 | 
| 天津\(T_1\) | — | — | 100 | 170 | 300 | 500 | 
| 武汉\(T_2\) | — | — | 315 | 130 | 150 | 400 | 
| 需求量 | 500 | 400 | 300 | 400 | 100 | 
建立转运矩阵
| 序号 | 沈阳1 | 郑州 2 | 天津3 | 武汉4 | 北京5 | 上海6 | 广州7 | 发送量 | |
|---|---|---|---|---|---|---|---|---|---|
| 产地 | 1 | 0 | \(M\) | 210 | 470 | \(M\) | \(M\) | \(M\) | 800+500 | 
| 2 | \(M\) | 0 | 230 | 160 | \(M\) | \(M\) | \(M\) | 800+300 | |
| 中转 | 3 | \(M\) | \(M\) | 0 | \(M\) | 100 | 170 | 300 | 800 | 
| 4 | \(M\) | \(M\) | \(M\) | 0 | 315 | 130 | 100 | 800 | |
| 销地 | 5 | \(M\) | \(M\) | \(M\) | \(M\) | 0 | \(M\) | \(M\) | 800 | 
| 6 | \(M\) | \(M\) | \(M\) | \(M\) | \(M\) | 0 | \(M\) | 800 | |
| 7 | \(M\) | \(M\) | \(M\) | \(M\) | \(M\) | \(M\) | 0 | 800 | |
| 接收量 | 800 | 800 | 800 | 800 | 800+300 | 800+400 | 800+100 | 
#修改上面程序的数据即可,f是程序运算中的无穷,也就是运筹的M
if __name__ == '__main__':
    f=10000000  #float("inf")
    costs = np.array([[0, f, 210, 470, f, f, f],
                      [f, 0, 230, 160, f, f, f],
                      [f, f, 0, f, 100, 170, 300],
                      [f, f, f,0, 315, 130, 150],
                      [f, f, f,f, 0, f, f],
                      [f, f, f, f, f, 0, f],
                      [f, f, f, f, f, f, 0]])
    max_plant = [1300, 1100, 800, 800, 800, 800, 800]
    max_cultivation = [800, 800, 800, 800, 1100, 1200, 900]
最小值为258000.0
各变量的取值为: 
[[800.0, 0.0, 500.0, 0.0, 0.0, 0.0, 0.0],
 [0.0, 800.0, 0.0, 300.0, 0.0, 0.0, 0.0],
 [0.0, 0.0, 300.0, 0.0, 300.0, 200.0, 0.0],
 [0.0, 0.0, 0.0, 500.0, 0.0, 200.0, 100.0],
 [0.0, 0.0, 0.0, 0.0, 800.0, 0.0, 0.0],
 [0.0, 0.0, 0.0, 0.0, 0.0, 800.0, 0.0],
 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 800.0]]
四、练习题
4.1 练习1
某种物资需从甲、乙两个产地运往A,B和C三个销地,并允许中间经过某产地或销地转运,其网络图如下:
 
已知甲和乙的供应量各为100和200,A、B和C的需求量均为100,线段(弧)上的数字为单位运费。试求(1)用表格形式列出此问题的运输模型;(2)求此问题的最优解。
4.2 练习2
某种物资需从甲、乙两个产地运往A,B和C三个销地,并允许中间经过某产地或销地转运,其网络图如下:
 
已知甲和乙的供应量各为100和200,A、B和C的需求量分别为100、100和170,线段(弧)上的数字为单位运费。试求(1)用表格形式列出此问题的运输模型;(2)求此问题的最优解。(解题提示:可添加虚拟产地化为标准的转运运输问题,如练习1)
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号