转运运输问题——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)