基于cvxpy的运输问题(线性规划)

问题:已知某种商品m个仓库的存货量,n个客户对该商品的需求量,单位商品运价。试确定m个仓库到n个客户的商品调运数量,使总的运输费用最小。

输入格式:

第一行两个数m,n
第2行到第m+1行 对应商品运价
第m+2行对应需求量
第m+3行对应存货量

输出格式:

精确到小数点后两位

输入样例:

在这里给出一组输入。例如:

6 8  
6    2    6    7    4    2    5    9  
4    9    5    3    8    5    8    2  
5    2    1    9    7    4    3    3  
7    6    7    3    9    2    7    1  
2    3    9    5    7    2    6    5  
5    5    2    2    8    1    4    3  
35    37    22    32    41    32    43    38  
60  55  51  43  41  52 

输出样例:

在这里给出相应的输出。例如:

664.00

我们将这个问题分为两个模块,第一部分是很简单的输入数据部分,第二部分就是基于cvxpy的线性规划问题。


一、数据输入(这里的操作基本都差不多,所以放在一起讲)

import cvxpy as cp
import numpy as np

m, n = [eval(x) for x in input().split()]

c = np.zeros((m, n))
for i in range(m):
    c[i, :] = [eval(x) for x in input().split()]

demand = [eval(x) for x in input().split()]  # demand 代表需求量
inventory = [eval(x) for x in input().split()]  # inventory代表存货量

input.split()函数将我们输入的数据按空格进行分隔,并返回分割后的字符串列表。再调用for循环并通过eval函数将列表里的每个str改为int,再分别给m和n赋值。

c=np.zeros((m,n))创建了一个元素全为0的m*n的矩阵,然后通过for循环和c[i,:]=[eval(x) for x in input().split()]给矩阵c里的第i行元素赋值。

下面的demand和inventory分别代表客户需求量和仓库存货量。

二、cvxpy线性规划

x = cp.Variable((m, n))
obj = cp.Minimize(cp.sum(cp.multiply(c, x)))

con1 = cp.sum(x, axis=1) <= inventory
con2 = cp.sum(x, axis=0) == demand
con3 = x >= 0
cons = [con1, con2, con3]

prob = cp.Problem(obj, cons)
prob.solve()

print("{0:.2f}".format(prob.value), end='')

 cvxpy库使用较难,相关资料也比较难理解,下面是(cvxpy库的官方介绍),本人使用的是Pycharm2022,在安装cvxpy库过程中曾经遇到过安装卡顿问题,可以通过更换镜像源的方法解决(2022 Pycharm 不同版本镜像源添加)。

首先我们要明白使用cvxpy库的三要素——需求变量、目标函数、约束条件。


①需求变量

在线性规划运输问题中,我们最终要求解的是最小的总运输费用,因为从每个仓库到每个客户的单位运价已经给出,所以这里我们要先构造一个同样为m*n的矩阵来存储最终解矩阵(为使总运输费用最小每个仓库对每个客户的商品供给量)

x = cp.Variable((m, n))

生成了m行n列的矩阵,且为变量(可以理解为创建了一个全为变量的矩阵)

上述过程可以理解为设未知数求解方程

obj = cp.Minimize(cp.sum(cp.multiply(c, x)))

②目标函数

cp.multiply函数将单位运价矩阵c和解矩阵x相乘(这里的乘是对应位置元素相乘),得到的结果是运输费用矩阵。

multipy和*含义一样,前者是函数,后者是运算符号,含义是矩阵元素对应相乘,

而dot和@含义一样,前者是函数,后者是运算符号,含义是线性代数中的矩阵乘法。

这里的cp.sum()是将矩阵中所有的元素进行求和,再调用Minimize函数得到的结果就是最终要求的最小总运输费用。

sum函数用法为:当不含axis参数时,sum(a)是将矩阵a中所有元素进行求和。而当含有axis参数时,sum(a,axis=0/1),axis=0,对于多维矩阵来说,是将每一个列向量相加,而当axis=1时,是将每一个行向量相加(详见sum函数用法)。


③约束条件

我们在上述过程中创建的x矩阵为m*n的最终解矩阵(为使总运输费用最小每个仓库对每个客户的商品供给量),需对其添加约束条件。

con1 = cp.sum(x, axis=1) <= inventory
con2 = cp.sum(x, axis=0) == demand
con3 = x >= 0
cons = [con1, con2, con3]

con1=cp.sum(x,axis=1)<=inventory将解矩阵中每一个行向量相加,每一个对应的和都要小于等于inventory(存货量)中对应位置的存货量。

con2=cp.sum(x,axis=0)=demand将解矩阵中每一个列向量相加,每一个对应的和都要等于demand(需求量)中对应位置的需求量。

con3=x>=0解矩阵中每一元素都要大于等于0。

prob = cp.Problem(obj, cons)
prob.solve()

print("{0:.2f}".format(prob.value), end='')

最后调用cp.Problem函数,obj为目标函数,cons为约束条件,构建prob,并通过prob.solve()求解。

得到的输出结果如下

 注意这里最终的输出要是prob.value

我们再看一下求解过程中要用的解矩阵x的值print(x.value)

完整代码如下:

import cvxpy as cp
import numpy as np

m, n = [eval(x) for x in input().split()]

c = np.zeros((m, n))
for i in range(m):
    c[i, :] = [eval(x) for x in input().split()]

demand = [eval(x) for x in input().split()]  # demand 代表需求量
inventory = [eval(x) for x in input().split()]  # inventory代表存货量

x = cp.Variable((m, n))
obj = cp.Minimize(cp.sum(cp.multiply(c, x)))

con1 = cp.sum(x, axis=1) <= inventory
con2 = cp.sum(x, axis=0) == demand
con3 = x >= 0
cons = [con1, con2, con3]

prob = cp.Problem(obj, cons)
prob.solve()

print("{0:.2f}".format(prob.value), end='')

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vargent_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值