提示:本文主要是关于python的实现,不纠结于原理部分
目录
文章目录
前言
一、理论部分
1.最小元素法
2.沃格尔(Vogel)法
二、最小元素法实现
1.数据准备
2.代码主体部分
三、沃格尔(Vogel)法代码实现
1.数据准备
2.代码主体部分
四、完整代码
总结
运输问题是一种线性规划模型,如果使用单纯形法,那么对每个约束都需要引入一个人工变量,因此为更好的求解运输问题,需要有一种新方法。
表上作业法是求解运输问题的一种简便而有效的方法,其整体的迭代步骤为:得到初始解;对解进行判定,若不是最优解,则改进;再判定;直到得到运输问题的最优解为止。
提示:以下是本篇文章正文内容,下面案例可供参考
得到初始可行解有两种常用的方法:最小元素法和沃格尔(Vogel)法。
最小元素法是基于优先满足单位运价最小的供销业务,是一种贪心思想。
沃格尔法可以简单总结为找到最大罚数的行(列),在该行(列)种找到最小的运价,满足该运价对应的供销关系,不断迭代。
上面只是简单介绍一下两个方法的思想,要想明白可以找找相关资料,个人感觉原理很简单。下面就直接进入正题。Coding!!!
产量、销量、产地和销地间的成本矩阵、设置一个极大数、初始化初始解。
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 #极大数
这里的python实现思想是:
1、找到最小运价的索引;
2、判断该索引对应的产地的产量和销地的销量大小关系,以此确定该索引下的运输量;
3、将该索引对应的剩余产量、剩余销量数据更新,并且将已经满足运输条件的行(列)成本全部提高为一个极大数(该操作替换表上作业法里面的删除操作);
4、条件判定,若所有的成本都已经不小于这个极大数,则跳出循环,否则跳入步骤1。
代码如下:
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
产量、销量、产地和销地间的成本矩阵、设置一个极大数、初始化初始解、罚数矩阵。
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]]) #成本
c=copy.deepcopy(C)
maxNumber=10000 #极大数
X=np.zeros((supplyNum,demandNum)) #初始解
numPunish=[0]*(supplyNum+demandNum) #整体罚数
代码的逻辑部分如下:
1、求解行、列罚数,并将其存储在一个列表中;
2、找到最大罚数对应的行(列),确定该行(列)中最小运价的索引;
3、判断该索引对应的产地的产量和销地的销量大小关系,以此确定该索引下的运输量;
4、将该索引对应的剩余产量、剩余销量数据更新,并且将已经满足运输条件的行(列)成本全部提高为一个极大数(该操作替换表上作业法里面的删除操作);
5、条件判定,若所有销量和产量都为0(即所有的供需关系得到满足),则跳出循环,否则跳入步骤1。
上面的步骤3、4、5和最小元素法一样。其中步骤5的判定方法也等同于最小元素法的判定方法。
代码如下:
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 maxIndexB[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
"""
运输问题初始解的构造方式有两种:最小元素法、沃格尔法
"""
'----------------------------------------最小元素法------------------------------------' \
'最小元素法是指有限满足单位运价最小的供销服务'
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 (cB[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,c1)
print('Vogel法得到的初始解为:')
print(solutionVogel)
print('Vogel法得到的总运费为:',(C*solutionVogel).sum())
该文所针对的是关于供销平衡问题的初始解的实现,对于不平衡的问题,其实只要对成本矩阵和供需量变换一下就可以。
后面会继续写关于检验方法、改进方法的python实现。最后也打算出一期python调用Gurobi求解运输模型的文章。