表上作业法求解运输问题----python生成初始解

提示:本文主要是关于python的实现,不纠结于原理部分

目录

文章目录

前言

一、理论部分

1.最小元素法

2.沃格尔(Vogel)法

二、最小元素法实现

1.数据准备

2.代码主体部分

三、沃格尔(Vogel)法代码实现

1.数据准备

2.代码主体部分

四、完整代码

总结



前言

运输问题是一种线性规划模型,如果使用单纯形法,那么对每个约束都需要引入一个人工变量,因此为更好的求解运输问题,需要有一种新方法。

表上作业法是求解运输问题的一种简便而有效的方法,其整体的迭代步骤为:得到初始解;对解进行判定,若不是最优解,则改进;再判定;直到得到运输问题的最优解为止。


提示:以下是本篇文章正文内容,下面案例可供参考

一、理论部分

得到初始可行解有两种常用的方法:最小元素法和沃格尔(Vogel)法。

1.最小元素法

最小元素法是基于优先满足单位运价最小的供销业务,是一种贪心思想。

2.沃格尔(Vogel)法

沃格尔法可以简单总结为找到最大罚数的行(列),在该行(列)种找到最小的运价,满足该运价对应的供销关系,不断迭代。

上面只是简单介绍一下两个方法的思想,要想明白可以找找相关资料,个人感觉原理很简单。下面就直接进入正题。Coding!!!

二、最小元素法实现

1.数据准备

产量、销量、产地和销地间的成本矩阵、设置一个极大数、初始化初始解。

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       #极大数

2.代码主体部分

这里的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

三、沃格尔(Vogel)法代码实现

1.数据准备

产量、销量、产地和销地间的成本矩阵、设置一个极大数、初始化初始解、罚数矩阵。

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)       #整体罚数

2.代码主体部分

代码的逻辑部分如下:

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求解运输模型的文章。

你可能感兴趣的:(python,算法)