运筹系列93:VRP精确算法

news2024/12/27 1:17:08

1. MTZ模型

MTZ是Miller-Tucker-Zemlin inequalities的缩写。除了定义是否用到边 x i j x_{ij} xij外,还需要定义一个 u i u_i ui用来表示此时车辆的当前载货量。注意这里x变量需要定义为有向。
这里定义为pickup问题,代码为:

using JuMP, HiGHS

k = 3 # number of vehicles
N = 11 # number of points, 0 as depot
Q = 4 # vehicle capacity
q = ones(Int,N);q[1]=0 # demand
CVRP = Model(HiGHS.Optimizer)
set_silent(CVRP)
@variable(CVRP,x[1:N,1:N],Bin)
@variable(CVRP,u[1:N],lower_bound = 0, upper_bound = Q)
# 约束1:出度约束
for i in 2:N
    @constraint(CVRP, sum(x[i,1:i-1]) + sum(x[i,i+1:N]) == 1)
    @constraint(CVRP, sum(x[1:i-1,i]) + sum(x[i+1:N,i]) == 1)
end
@constraint(CVRP, sum(x[1,1:N]) == k)
# 约束2:流量约束。若存在i->j,则u_j-u_i==q_j;否则u_j-q_j和u_i没有关系。此外,需要有u_j-q_j>=0
for i=2:N, j=[2:i-1;i+1:N]
    @constraint(CVRP,u[i] - u[j] + Q*x[i,j] <= Q-q[j])
end
for i in 2:N
    @constraint(CVRP,q[i] <= u[i] <= Q)
end

@objective(CVRP,Min, sum(x[i,j]*distmat[i,j] for i=1:N,j=1:N))
@time optimize!(CVRP)

MTZ的求解速度不快,10个点3辆车都需要3秒左右时间。

2. 分支定界法

使用Two-index vehicle flow formulations。按照tsp的方式使用行生成法速度极慢(cut的效率太低),因此考虑使用branch-and-cut直接求解。需要cut的主要有2个:1)容量约束;2)subtour约束。如下例子:

using TSPLIB,JuMP, HiGHS, Distances
N = 13
Q = 4
k = 3
m = Model(HiGHS.Optimizer)
set_silent(m)
@variable(m, x[1:N,1:N]>=0,Bin)
@objective(m, Min, sum(x[i,j]*distmat[i,j] for i=1:N,j=1:N))
@constraint(m, x[1,1] == 0)
@constraint(m, sum(x[1,j] for j in 2:N) == k)
@constraint(m, sum(x[j,1] for j in 2:N) == k)
for i=2:N 
    for j in 1:N;@constraint(m, x[i,j]+x[j,i] <= 1);end
    @constraint(m, sum(x[i,j] for j in 1:N) == 1)
    @constraint(m, sum(x[j,i] for j in 1:N) == 1)
end
optimize!(m)
draw_vrp(x)

在这里插入图片描述

接下来定义寻找tour的函数,以及branch and cut的代码:

# find all subtours
function tours(x)
    g = JuMP.value.(x)
    # 第一步,找到所有从1出发的tour
    abnormal_paths = []
    paths = []
    path = [1]
    left = collect(1:N)
    while true
        v, idx = findmax(g[path[end],left])
        if v==0
            break
        else
            g[left[idx],path[end]]=0
            g[path[end],left[idx]]=0
            push!(path,left[idx])
        end
        if path[end]==1
            if length(path)>Q+2;push!(abnormal_paths,path);end
            push!(paths,path)
            path = [1]
            setdiff!(left,path[2:end-1])
        end
    end
    # 第二步,找到所有孤立的环(subtour)
    left = collect(1:N)
    for path in paths;setdiff!(left,path);end
    while length(left)>0   
        path = [left[1]]
        while true
            v, idx = findmax(g[path[end],left])
            if idx == 1
                break
            else
                g[left[idx],path[end]]=0
                g[path[end],left[idx]]=0
                push!(path,left[idx])
            end
        end
        setdiff!(left,path)
        push!(paths,path)
        push!(abnormal_paths,path)
    end
    return paths,abnormal_paths
end
    
paths,abnormal_paths = tours(x)
while length(abnormal_paths) > 0
    for path in paths
        s = setdiff(path,1)
        sn = setdiff(2:N,s)
        @constraint(m, sum(x[i,j] for i in s, j in setdiff(1:N,s)) >= ceil(length(s)/Q))
        @constraint(m, sum(x[i,j] for i in sn, j in setdiff(1:N,sn)) >= ceil(length(sn)/Q))
    end
    optimize!(m)
    paths,abnormal_paths = tours(x)
end
draw_vrp(x)

在这里插入图片描述

3. set-partitioning方法

方法很直观,把所有的子路径用TSP问题求解(使用Concorde库),然后用set-partitioning方法选择最合适的几条路线组合成VRP的结果。

using JuMP, HiGHS, Combinatorics, Concorde 

k = 3
N = 13 #34
Q = 4 #13

function getRoutes(k,N,Q)
    Qm = N-1-(k-1)*Q
    route_dists = Dict()
    # 求解所有子路径的最优解
    for q in Qm:Q
        for c in combinations(2:N,q)
            c_index_tour,c_tour_length = Concorde.solve_tsp(floor.(Int,distmat[[1;c],[1;c]].*100)) 
            c_tour = [1;c][c_index_tour]
            route_dists[c_tour] = c_tour_length
        end
    end
    route_dists
end
@time route_dists = getRoutes(k,N,Q);
CVRP = Model(HiGHS.Optimizer)
set_silent(CVRP)
routes = collect(keys(route_dists))
route_dists = collect(values(route_dists))
rn = length(routes)
@variable(CVRP,x[1:rn],Bin)
@objective(CVRP,Min, sum(x[i]*route_dists[i] for i in 1:rn))
a = zeros(Int,rn,N)
for i in 1:rn,j in routes[i];a[i,j]=1;end
for j in 2:N;@constraint(CVRP,sum(x[i]*a[i,j] for i in 1:rn)==1);end
@constraint(CVRP,sum(x)==k)
@time optimize!(CVRP)
rs = routes[findall(x->x>0.1,value.(x))]
plt.figure(figsize=(10,7)) 
plt.scatter(pos[1:N,1],pos[1:N,2],c="red")
for i in 1:N;plt.text(pos[i,1], pos[i,2], i);end
for r in rs
    l = pos[[r;1],:]
    PyPlot.plot(l[:,1], l[:,2], color="b")
end

在这里插入图片描述

4. 关于测试数据

测试案例可参考 http://vrp.atd-lab.inf.puc-rio.br/index.php/en/。
我们这里用的数据为:

pos = [121.472641	31.231707
123.429092	41.796768
125.324501	43.886841
126.642464	45.756966
116.405289	39.904987
117.190186	39.125595
111.75199	40.84149
106.23248	38.48644
112.549248	37.857014
114.502464	38.045475
117.000923	36.675808
113.665413	34.757977
108.948021	34.263161
114.298569	30.584354
118.76741	32.041546
117.283043	31.861191
112.982277	28.19409
115.892151	28.676493
120.15358	30.287458
119.306236	26.075302
113.28064	23.125177
121.520076	25.030724
110.19989	20.04422
108.320007	22.82402
106.504959	29.533155
102.71225	25.040609
106.713478	26.578342
104.065735	30.659462
103.83417	36.06138
101.77782	36.61729
91.1145	29.64415
87.61688	43.82663
114.16546	22.27534
113.54913	22.19875];

function dis(i,j)
    A = pos[i,:];B = pos[j,:]
    sqrt(sum((A-B).^2))
end

function drawTree(t,n)
    plt.figure(figsize=(10,7)) 
    plt.scatter(pos[1:n,1],pos[1:n,2],c="red")
    for i in 1:n;plt.text(pos[i,1], pos[i,2], i);end
    for i in 1:length(t)
        l = pos[collect(t[i]),:]
        PyPlot.plot(l[:,1], l[:,2], color="b")
    end
end

function draw_vrp(x)
    xv = value.(x)
    t = []
    for i in 1:size(x)[1],j in 1:size(x)[1]
        if xv[i,j]>0.1;push!(t,(i,j));end
    end
    drawTree(t,size(x)[1])
end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1857224.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CentOS7】Linux安装Docker教程(保姆篇)

文章目录 查看是否已安装卸载&#xff08;已安装过&#xff09;docker安装友情提示 更多相关内容可查看 注&#xff1a;本篇为Centos7安装Docker&#xff0c;若为其他系统请理性参考 查看是否已安装 如果已安装&#xff0c;请卸载重新安装 docker --version这里显示已安装 …

Web网页端IM产品RainbowChat-Web的v7.0版已发布

一、关于RainbowChat-Web RainbowChat-Web是一套Web网页端IM系统&#xff0c;是RainbowChat的姊妹系统&#xff08;RainbowChat是一套基于开源IM聊天框架 MobileIMSDK (Github地址) 的产品级移动端IM系统&#xff09;。 ► 详细介绍&#xff1a;http://www.52im.net/thread-2…

基于Java医院药品交易系统详细设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;…

AI大模型战争:通用与垂直,谁将领跑未来?

文章目录 &#x1f4d1;引言一、通用大模型&#xff1a;广泛适用&#xff0c;实力不容小觑1.1 强大的泛化能力1.2 广泛的适用场景 二、垂直大模型&#xff1a;专注深度&#xff0c;精准解决问题2.1 深度专注&#xff0c;精准度高2.2 快速落地与普及 三、通用与垂直&#xff1a;…

SFP4006-ASEMI无人机专用SFP4006

编辑&#xff1a;ll SFP4006-ASEMI无人机专用SFP4006 型号&#xff1a;SFP4006 品牌&#xff1a;ASEMI 封装&#xff1a;TO-247 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;40A 最大循环峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;600V 最大正向…

SVN学习(004 subversive操作和解决冲突)

尚硅谷SVN高级教程(svn操作详解) 总时长 4:53:00 共72P 此文章包含第42p-第p43的内容 操作 新建一个teacher类 添加到版本库&#xff08;也可以忽略这步 直接提交&#xff09; 资源-》右键-》team-》提交 另一个用户进行更新 资源-》右键-》team-》更新 解决冲突 用…

HTML【介绍】

HTML【介绍】 一、Web认知 1.网页组成 文字、图片、音频、视频、超链接 2.五大浏览器 IE浏览器、火狐浏览器&#xff08;Firefox&#xff09;、谷歌浏览器&#xff08;Chrome&#xff09;、Safari浏览器、欧朋浏览器&#xff08;Opera&#xff09; 3.Web标准的构成 HTML…

上海医疗学术会议小程序开发的优势与主要功能

现如今&#xff0c;随着互联网科技的进步与发展&#xff0c;越来越的医务工作者开始组织参加医疗学术会议&#xff0c;而同大数据相结合&#xff0c;出现的上海医疗学术会议小程序开发则为医疗学术会议带来了新的活力&#xff0c;使其组织流程更加规范&#xff0c;便捷、呈现效…

性能升级,这波够带劲!高性价比首选:18位高速多功能同步数据采集卡

PXIe9752系列是一款高性能、多功能的数据采集卡&#xff0c;其中包含了模拟输入、模拟输出、数字量输入输出以及计数器。专为复杂的测试和测量应用设计&#xff0c;为用户提供更多的功能选择和灵活性。 主要参数 产品优势 高精度:能够捕捉微小信号变化,提高测量分辨率。 高…

[职场] 提升学历考研再就业有必要吗 #其他#知识分享

提升学历考研再就业有必要吗 有很多人觉得自己学历不够高&#xff0c;求职第一关可能就通过不了。因此想要继续攻读&#xff0c;最近有人问小编提升学历考研有必要吗&#xff1f;“硕士学历和三年的工作经验哪个更重要?” 这个还是要针对具体岗位而言。综合类型的岗位往往不需…

VsCode-PlatformIO 开发环境搭建

在VScode中搜索PlatformIO&#xff0c;然后点击install 安装即可 安装后重新打开vscode&#xff0c;会出现如下界面。

益百分4.0版益生君重磅来袭,为您保驾护航

益百分4.0版益生君重磅来袭&#xff0c;为您保驾护航 暑期来临&#xff0c;很多人们终于等来了一年中最幸福的时刻&#xff0c;三五成群、结伴旅游成为他们选择欢度暑假的方式。 全国各地的旅游景点也迎来了旺季&#xff0c;各大旅游公司也推出了各种各样的旅游团购活动&#x…

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题&#xff1a;第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

基于图扑 HT for Web 实现拓扑关系图

拓扑结构在计算机网络设计和通信领域中非常重要&#xff0c;因为它描述了网络中的设备&#xff08;即“点”&#xff09;如何相互连接&#xff08;即通过“线”&#xff09;。这种结构不仅涉及物理布局&#xff0c;即物理拓扑&#xff0c;还可以涉及逻辑或虚拟的连接方式&#…

苹果手机备忘录怎么长截屏或者导出

在快节奏的生活中&#xff0c;手机备忘录已成为我们随时记录重要信息和灵感的得力助手。然而&#xff0c;当我们想要保存或分享备忘录中的长内容时&#xff0c;苹果手机的截屏功能似乎就显得有些捉襟见肘了。 那么&#xff0c;苹果手机备忘录如何进行长截屏或者导出呢&#xf…

每日热榜资源

获取更多资源&#xff0c;请关注公众号&#xff1a;阿宇的编程之旅&#xff0c;回复‘书签’获取 划水摸鱼官网 网站名称&#xff1a;划水摸鱼官网网址&#xff1a;划水摸鱼官网介绍&#xff1a;提供休闲放松的内容&#xff0c;让你在忙碌之余享受片刻的宁静。 鱼塘热榜 网…

谷歌浏览器截图

一 右击&#xff0c;然后点击检查&#xff1b; 二 然后ctrlshiftp,运行命令&#xff1b; 三 3.1搜索截图&#xff1a; 如果你设置为中文&#xff0c;搜索截图&#xff0c;选择你想要的截图类型&#xff1b; 如果你是在英文情况下&#xff1a; 输入capture full size 来过滤…

驾照减分考试搜题软件?分享四个可以搜答案的软件 #其他#笔记#经验分享

大学生们可以通过使用搜题软件&#xff0c;快速找到自己遇到的问题的答案&#xff0c;提高学习效率&#xff0c;以下分享各类型的供大家学习。 1.彩虹搜题 这是个微信公众号 学生或者是成年人使用非常广的一款学习应用软件&#xff0c;里面包含了各行各业的海量题库&#xf…

uni-app移动端使用uni-file-picker上传图片时通过canvas添加拍摄时间等水印信息

实现效果&#xff1a; 添加的照片添加水印信息 实现方式&#xff1a; 将添加水印的方法抽离成组件&#xff0c;为Vue文件&#xff0c;方便复用&#xff0c;在父组件中直接引用即可实现水印效果。 子组件&#xff1a;waterMarker.vue 此为添加水印的组件文件&#xff0c;…