产销平衡
运输问题模型
在运输问题中,我们有m个工厂生产物品, n个目的地(商店,企业)需要这些物品。
这些物品需要从出发地运输到目的地,这有相关的成本。
目标是使运输总成本最小化。
表上作业法求解
求解步骤:
步骤一:求初始基本可行解(西北角法、最小元素法、伏格尔法)
步骤二:求检验数并判断(闭回路法、位势法)
步骤三:调整运量(闭回路法)
步骤四:重复步骤二、三,直到求得最优解
西北角法(可能导致运费偏大)
Python求解
#运输问题初始解的构造方式有两种:最小元素法、沃格尔法
#'----------------------------------------最小元素法------------------------------------' \
import numpy as np
import copy
supplyNum = 3 # 供应商数量
demandNum = 4 # 需求商数量
A = np.array([16, 10, 22]) # 产量
B = np.array([8, 14, 12, 14]) # 销量
C = np.array([[4, 12, 4, 11], [2, 10, 3, 9], [8, 5, 11, 6]]) # 成本
X = np.zeros((supplyNum, demandNum)) # 初始解
c = copy.deepcopy(C)
maxNumber = 10000 # 极大数
def pivot(A, B, c, X):
index = np.where(c == np.min(c)) # 寻找最小值的索引
minIndex = (index[0][0], index[1][0]) # 确定最小值的索引
# 确定应该优先分配的量,并且改变价格
if A[index[0][0]] > B[index[1][0]]:
X[minIndex] = B[index[1][0]]
c[:, index[1][0]] = maxNumber # 改变价格
A[index[0][0]] = A[index[0][0]] - B[index[1][0]]
B[index[1][0]] = 0 # 改变销量
else:
X[minIndex] = A[index[0][0]]
c[index[0][0], :] = maxNumber
B[index[1][0]] = B[index[1][0]] - A[index[0][0]]
A[index[0][0]] = 0
return A, B, c, X
def minimumElementMethod(A, B, c, X):# 最小元素法
while (c < maxNumber).any():
A, B, c, X = pivot(A, B, c, X)
return X
solutionMin = minimumElementMethod(A, B, c, X)
print('最小元素法得到的初始解为:')
print(solutionMin)
print('最小元素法得到的总运费为:', ((solutionMin * C).sum()))
'-----------------------------------Vogel法---------------------------------'
supplyNum = 3 # 供应商数量
demandNum = 4 # 需求商数量
A = np.array([16, 10, 22]) # 产量
B = np.array([8, 14, 12, 14]) # 销量
C = np.array([[4, 12, 4, 11], [2, 10, 3, 9], [8, 5, 11, 6]]) # 成本
X = np.zeros((supplyNum, demandNum)) # 初始解
c = copy.deepcopy(C)
numPunish = [0] * (supplyNum + demandNum) # 整体罚数
def pivot(X, A, B, C):
# 求解罚数,其中列罚数排在行罚数后面
for i in range(supplyNum):
sortList = np.sort(C[i, :])
numPunish[i] = sortList[1] - sortList[0]
for i in range(demandNum):
sortList = np.sort(C[:, i])
numPunish[i + supplyNum] = sortList[1] - sortList[0]
maxIndex = np.argmax(numPunish) # 寻找最大罚数的索引
if maxIndex < supplyNum: #若最大的罚数属于行罚数
minIndex = np.argmin(C[maxIndex, :])
index = (maxIndex, minIndex) #得到最大罚数的一行中最小的运价
if A[maxIndex] > B[minIndex]: # 若产量大于销量
X[index] = B[minIndex] #更新解
C[:, minIndex] = maxNumber #将已经满足的一列中的运价增大替代删除操作
A[maxIndex] -= B[minIndex] # 更新剩余产量
B[minIndex] = 0 # 更新已经满足的销量
else:# 若销量大于产量
X[index] = A[maxIndex]
C[maxIndex, :] = maxNumber
B[minIndex] -= A[maxIndex] # 更新销量
A[maxIndex] = 0
else:# 若最大的罚数为列罚数
minIndex = np.argmin(C[:, maxIndex - supplyNum]) # 这时maxIndex-supplyNum是罚数最大的列
index = (minIndex, maxIndex - supplyNum)
if A[minIndex] > B[maxIndex - supplyNum]: # 这里是产量大于销量,因此有限满足销量
X[index] = B[maxIndex - supplyNum]
C[:, maxIndex - supplyNum] = maxNumber
A[minIndex] -= B[maxIndex - supplyNum]
B[maxIndex - supplyNum] = 0
else:
X[index] = A[minIndex]
C[minIndex, :] = maxNumber
B[maxIndex - supplyNum] -= A[minIndex]
A[minIndex] = 0
return X, A, B, C
# 沃格尔法得到初始解
def Vogel(A, B, C):
X = np.zeros((supplyNum, demandNum)) # 初始解
numPunish = [0] * (supplyNum + demandNum) # 整体罚数
# 迭代,直到所有的产量和销量全部满足
while (A != 0).any() and (B != 0).any():
X, A, B, C = pivot(X, A, B, C)
return X
# 上面对于条件的判断,还需要对销量和需求量进行改变
# solutionVogel = Vogel(A, B, c)
# print('Vogel法得到的初始解为:')
# print(solutionVogel)
# print('Vogel法得到的总运费为:', (C * solutionVogel).sum())
产销不平衡
转化为产销平衡问题,然后使用表上作业法进行求解。