带时间窗车辆路径问题丨论文复现:改进粒子群算法求解

路径优化相关文章

  • 1、路径优化历史文章
  • 2、路径优化丨带时间窗和载重约束的CVRPTW问题-改进遗传算法:算例RC108
  • 3、路径优化丨带时间窗和载重约束的CVRPTW问题-改进和声搜索算法:算例RC108
  • 4、路径优化丨复现论文-网约拼车出行的乘客车辆匹配及路径优化
  • 5、多车场路径优化丨遗传算法求解MDCVRP问题
  • 6、论文复现详解丨多车场路径优化问题:粒子群+模拟退火算法求解
  • 7、路径优化丨复现论文外卖路径优化GA求解VRPTW
  • 8、多车场路径优化丨蚁群算法求解MDCVRP问题
  • 9、路径优化丨复现论文多车场带货物权重车辆路径问题:改进邻域搜索算法
  • 10、多车场多车型路径问题求解复现丨改进猫群算法求解
  • 11、带时间窗车辆路径问题论文复现:改进粒子群算法求解

带时间窗的车辆路径问题

可描述为:车场有若干车辆、存在若干需求点、车辆从车场往返服务需求点。其中:车辆存在装载体积约束,数量约束,车辆在时间窗之外有惩罚成不。本文假设:

(1)物流配送中心数量单一,且配送中心的货物数量足够,不存在缺货现象;

(2)物流配送中心具有一定数量的同种类型车辆;

(3)各个客户点的地理位置、所需货物数量、时间窗限制等基本信息已知;

(4)配送车辆只负责将货物送至给顾客,不提供换货及退货服务;

(5)配送车辆的速度随路况的变化而变化。

详细描述见参考文献

数学模型

具体模型见参考文献,目标函数是不变成本和可变成本之和。不变成本是每辆车的固定成本,可变成本是每辆车的运行成本,和经过的客户点有关系。


文献没给Ei和Li的具体值,只计算了c1,c2,c3,没计算满意度

数据

论文数据,23个客户,复制数据到excel:

代码运行环境

windows系统,python3.6.0,第三方库及版本号如下:

numpy==1.18.5
matplotlib==3.2.1

第三方库需要在安装完python之后,额外安装,以前文章有讲述过安装第三方库的解决办法,点击下方文章名字跳转:

  • 1、代码运行环境说明

  • 2、第三方库安装方法

编码解码

编码

编码生成: 随机打乱客户编号

解码

一个车辆的解码如下:

1、 读出各车辆客户经纬度,货物体积,服务时间,时间窗;

2、 编码客户的第一个点时,计算车场到点的距离,其余点计算与上一个客户点的距离(经纬度距离乘111),根据车辆出发时间点取速度,根据速度计算时间,根据时间计算时间窗惩罚成本,更新运行成本,固定成本,惩罚成本;

3、每辆车遍历到最后一个点时,计算点到车场的距离,各项成本更新,解码结束:

代码如下:

    def decode(self, road):road_car = [[]]every_tj = 0for ro in road:tj1 = self.tj[ro]                # 对应客户点的体积if every_tj + tj1 <= self.V_max: # 如果添加新客户,能满足体积约束road_car[-1].append(ro)      # 对应车辆添加客户点every_tj += tj1              # 更新车辆装载体积else:                            # 如果添加新客户,不满足体积约束road_car.append([ro])        # 新车辆添加添加客户点every_tj = tj1               # 更新车辆装载体积c_window = 0c1, c2 = 0, 0for rd in road_car:end_j = np.array(self.jd)[rd]    # 一辆车对应的经度start_j = np.array([self.center[0]] + end_j.tolist()[:-1])        # 配送中心到倒数第二个点的经度end_w = np.array(self.wd)[rd]    # 一辆车对应的纬度start_w = np.array([self.center[1]] + end_w.tolist()[:-1])        # 配送中心到倒数第二个点的纬度d_gab = np.sqrt((end_j - start_j)**2 + (end_w - start_w)**2)*111  # 车辆按顺序的两点之间距离t_start = self.t_begin           # 起始时间count = 0for dg in d_gab:v_real = self.get_v(t_start) # 对应时间的运行速度t_start += dg/v_real         # 到达时间idx = rd[count]if t_start < self.te[idx]:   # 如果小于左时间窗,更新左时间窗成本c_window += (self.te[idx] - t_start)*self.ce  if t_start > self.tl[idx]:  # 如果大于左时间窗,更新右时间窗成本c_window += (t_start - self.tl[idx])*self.clt_start += self.tw[idx]     # 更新时间(加对应客户点的服务时间)count += 1                  # 客户点计数c2 += (count*self.g0 + self.gk)     # 固定成本dij = sum(d_gab) + np.sqrt((end_j[-1] - self.center[0])**2 + (end_w[-1] - self.center[1])**2)*111 # 运输距离加上会配送中心的距离c1 += dij*self.c                    # 运输成本return road_car, c1 + c2 + c_window

改进算法

粒子交叉

简单来说:选取父代编码相同长度的基因,初次交换;统计子代1与交换父代冲突的基因,子代2与父代冲突的基因,冲突基因再交换:

如上面的父代交换8,9,7,6 和2,5,6,7,得到子代1:[1,3,4,2,5,6,9,5,2],子代2:[4,8,3,8,9,7,6,7,1],子代1的冲突基因[2,5],子代2的冲突基因[8,7], 对应的冲突位置的基因再交换,即子代1的最后1个位置2换成,子代2的第2个位置的8;子代2的倒数第2个位置5换成,子代2的倒数第2个位置的7;

得到可行子代[1,3,4,2,5,6,9,7,8]和[4,2,3,8,9,7,6,7,1]

核心代码:

def cross(self, a, b):loc = random.sample(range(1, len(a)),2)loc.sort()idx1 = loc[0]idx2 = loc[1]a1 = a[:idx1-1]                             # 父代1前段a2 = a[idx2:]                               # 父代1后段b1 = b[:idx1-1]                             # 父代2前段b2 = b[idx2:]                               # 父代2后段aa = a[idx1-1:idx2]                         # 交换基因片段1bb = b[idx1-1:idx2]                         # 交换基因片段2aax,bbx = [], []for ax in aa:                               # 冲突基因1寻找if ax in b1 or ax in b2:bbx.append(ax)for bx in bb:                               # 冲突基因2寻找if bx in a1 or bx in a2: aax.append(bx)count = 0for au in aax:                              # 遍历冲突基因2if au in a1:                            # 如果冲突基因在父代1前段id1 = a1.index(au)                  # 找到冲突基因位置       bbxx = bbx[count]                   # 冲突基因1的交换基因if bbxx in b1:                      # 如果交换基因在父代2前段id2 = b1.index(bbxx)            # 交换对应位置基因a1[id1], b1[id2] = b1[id2], a1[id1] # 交换对应位置基因if bbxx in b2:                      # 如果冲突基因在父代2后段id2 = b2.index(bbxx)            # 交换基因位置a1[id1], b2[id2] = b2[id2], a1[id1] # 交换对应位置基因count += 1if au in a2:                            # 如果冲突基因在父代1后段,其余操作如上id1 = a2.index(au)bbxx = bbx[count]if bbxx in b1:id2 = b1.index(bbxx)a2[id1], b1[id2] = b1[id2], a2[id1]if bbxx in b2:id2 = b2.index(bbxx)a2[id1], b2[id2] = b2[id2], a2[id1]count += 1a = a1 + bb + a2                           # 交换好的基因片段拼接b = b1 + aa + b2return a, b

粒子交叉

比较简单,随机生成2个位置,交换对应基因:

def mul(self, a):loc = random.sample(range(len(a)),2)idx1 = loc[0]idx2 = loc[1]a[idx1], a[idx2] = a[idx2], a[idx1]        # 2个位置基因互换return a

粒子群算法

文献流程:

推文只有一个目标,具体的粒子群算法步骤如下:

(1)初始多个编码当做局部最优种群,初始多个编码当做迭代种群;

(2)迭代种群的个体与局部最优和全局最优进行交叉,然后自身进行变异;

(3)新解优于对应局部最优解时,更新局部最优解,另外更新迭代种群;

(4)根据局部最优解更新全局最优解;

(5)检查结束条件。若符合算法终止条件,则得到优化结果;否则,继续执行(2)

核心代码:

def total(self, num, generation, cd):ind_road = [cd.code() for i in range(num)]         # 初始多个编码当局部最优种群ind_f = [cd.decode(road)[-1] for road in ind_road] # 对应的局部最优值best_idx = ind_f.index(min(ind_f))                 # 全局最优索引gbest_road = ind_road[best_idx]                    # 全局最优路径T_road = [cd.code() for i in range(num)]           # 随机多个编码当初始种群result = [[0],[min(ind_f)]]for gen in range(generation):for n in range(num):road = T_road[n]road_i = ind_road[n]                       # 局部最优值road1, _ = self.cross(road, road_i)        # 局部最优交叉road2, _ = self.cross(road1, gbest_road)   # 全局最优交叉road2 = self.mul(road2)                    # 变异if cd.decode(road2)[-1] < ind_f[n]:        # 如果新解优与劣解ind_road[n] = road2                    # 更新局部最优ind_f[n] = cd.decode(road2)[-1]T_road[n] = road2best_idx =  ind_f.index(min(ind_f))gbest_road = ind_road[best_idx]                # 全局最优更新result[0].append(gen+1)result[1].append(min(ind_f))return gbest_road, result

结果

主函数

设计主函数如下:

import pandas as pd
import numpy as np
from code_decode import co_de
from pso import psodf = pd.read_excel('数据1.xlsx', sheet_name = '坐标时间窗')
df1 = pd.read_excel('数据1.xlsx', sheet_name = '行驶速度')jd, wd, tj, tw, te, tl = df['经度'], df['纬度'],  df['体积'], df['服务时间'],  df['最早时间'], df['最晚时间'],
td, v = df1['时间段'], df1['速度']
parm_data = [jd, wd, tj, tw, te, tl, td, v]center = [113.8321, 34.703993]                 # 配送中心经纬度
V_max = 8                                      # 最大容纳体积
t_begin = 8
ce, cl = 5, 15                                 # 早到和晚到的单位时间窗成本
g0, gk = 40, 210                               # 点位费和车辆的指派成本
c = 2.5                                        # 单位运行成本
parm_de = [center, V_max, t_begin, ce, cl, g0, gk, c]cd = co_de(parm_data, parm_de)
p = pso()
num, generation = 20, 13                       # 种群规模
gbest_road, result = p.total(num, generation, cd) # 算法结果
road_car, f = cd.decode(gbest_road)
print('\n结果验证:', f)
print('\n路径:', road_car)cd.draw(road_car, f)                         # 画路径图
cd.draw_change(result)                       # 画成本变化

运行结果

结果如下:

路径图:

成本随迭代次数的变化图如下:

还有优化空间,增大种群规模和迭代次数试试。

结论

本推文主要是对参考论文进行复现,有小改动:因为文献也没有给出相关参数,所以没有计算满意度,变成单目标问题,如果感兴趣可以设计参数进行测试,比较容易。其余基本是复现原文,详细介绍了交换和变异算子,可视化也有一些自己设计。

数据和算法皆可修改(考虑运行时间,推文把一些运行参数调低)。

参考文献:基于多目标混合粒子群算法的车辆路径优化_李琦翔

代码

为了方便和便于修改和测试,把代码在3个py文件里。

演示视频:

路径优化丨复现论文-带时间窗车辆路径问题论文复现:改进粒子群算法求解

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

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

相关文章

[C/C++入门][进制原理]27、计算机种的进制

各种信息进入计算机&#xff0c;都要转换成“0”和“1”的二进制形式。 计算机 采用二进制的原因是&#xff1a; 物理上容易实现&#xff0c;可靠性高。&#xff08;电子元件的通电和不通电就可以表示1和0&#xff0c;所以非常方便&#xff09;运算简单&#xff0c;通用性强。…

ELK日志分析系统部署文档

一、ELK说明 ELK是Elasticsearch&#xff08;ES&#xff09; Logstash Kibana 这三个开源工具组成&#xff0c;官方网站: The Elastic Search AI Platform — Drive real-time insights | Elastic 简单的ELK架构 ES: 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它…

Java 网络编程(TCP编程 和 UDP编程)

1. Java 网络编程&#xff08;TCP编程 和 UDP编程&#xff09; 文章目录 1. Java 网络编程&#xff08;TCP编程 和 UDP编程&#xff09;2. 网络编程的概念3. IP 地址3.1 IP地址相关的&#xff1a;域名与DNS 4. 端口号&#xff08;port&#xff09;5. 通信协议5.1 通信协议相关的…

如何免费用java c#实现手机在网状态查询

今天分享手机在网状态查询接口&#xff0c;该接口适用的场景非常广泛&#xff01;首先我们先讲下什么是手机在网状态&#xff1f;简单来说&#xff0c;就是你得手机号是否还在正常使用中&#xff0c;是否能够及时接收和回复信息&#xff0c;是否能够随时接听和拨打电话。如果你…

小白新手搭建个人网盘

小白新手搭建个人网盘 序云服务器ECS重置密码远程连接ECS实例 安装OwnCloud安装Apache服务PHP运行环境NAS挂载挂载验证操作体验 序 阿里云文件存储NAS&#xff08;Apsara File Storage NAS&#xff09;是一个可大规模共享访问&#xff0c;弹性扩展的分布式文件系统。本文主要是…

Python面试宝典第15题:岛屿数量

题目 在二维网格地图上&#xff0c;1 表示陆地&#xff0c;0 表示水域。如果相邻的陆地可以水平或垂直连接&#xff0c;则它们属于同一块岛屿。请进行编码&#xff0c;统计地图上的岛屿数量。比如&#xff1a;下面的二维网格地图&#xff0c;其岛屿数量为3。 基础知识 解决这类…

简约的悬浮动态特效404单页源HTML码

源码介绍 简约的悬浮动态特效404单页源HTML码,页面简约美观,可以做网站错误页或者丢失页面,将下面的代码放到空白的HTML里面,然后上传到服务器里面,设置好重定向即可 效果预览 完整源码 <!DOCTYPE html> <html><head><meta charset="utf-8&q…

高性能、安全、低碳绿色的趋势下,锐捷网络发布三擎云办公解决方案 3.0

桌面虚拟化作为云时代的主流和热门技术&#xff0c;已经取得了广泛应用。随着生成式 AI 爆炸式发展&#xff0c;CSDN 看到&#xff0c;人工智能正在引发计算、开发、交互三大范式的全面升级&#xff0c;技术开发或将迎来一次全新的科技变革周期&#xff0c;因此 VDI 云桌面随之…

组队学习——支持向量机

本次学习支持向量机部分数据如下所示 IDmasswidthheightcolor_scorefruit_namekind 其中ID&#xff1a;1-59是对应训练集和验证集的数据&#xff0c;60-67是对应测试集的数据&#xff0c;其中水果类别一共有四类包括apple、lemon、orange、mandarin。要求根据1-59的数据集的自…

Day16_集合与迭代器

Day16-集合 Day16 集合与迭代器1.1 集合的概念 集合继承图1.2 Collection接口1、添加元素2、删除元素3、查询与获取元素不过当我们实际使用都是使用的他的子类Arraylist&#xff01;&#xff01;&#xff01; 1.3 API演示1、演示添加2、演示删除3、演示查询与获取元素 2 Iterat…

[数据分析]脑图像处理工具

###############ATTENTION&#xff01;############### 非常需要注意软件适配的操作系统&#xff01;有些仅适用于Linux&#xff0c;可以点进各自软件手册查看详情。 需要自行查看支持的影像模态。 代码库和软件我没有加以区分。 不是专门预处理的博客&#xff01;&#xf…

HDU1005——Number Sequence,HDU1006——Tick and Tick,HDU1007——Quoit Design

目录 HDU1005——Number Sequence 题目描述 超时代码 代码思路 正确代码 代码思路 HDU1006——Tick and Tick 题目描述 运行代码 代码思路 HDU1007——Quoit Design 题目描述 运行代码 代码思路 HDU1005——Number Sequence 题目描述 Problem - 1005 超时代码…

QtC++ 设计模式(五)——状态模式

状态模式 序言理解源码 序言 设计模式只是一个抽象的设计模式方法&#xff0c;并不是一个固定使用的搭配&#xff0c;就算是普通switch语句&#xff0c;Map&#xff0c;乃至状态机都是状态模式的其中一种实现方法 状态模式看起来好像和策略模式差不多&#xff0c;主要是其的侧…

神经网络之多层感知机

目录 一、全连接层&#xff1a;二、单层感知机概念&#xff1a;三、多层感知机概念&#xff1a; 一、全连接层&#xff1a; 在神经网络中&#xff0c;全连接层就是每个神经元都与上一层的所有神经元相连接&#xff0c;即每个神经元都接收上一层所有神经元的输入&#xff0c;并…

分布式存储之 ceph 管理操作

一.资源池 Pool 管理 我们已经完成了 Ceph 集群的部署&#xff0c;但是我们如何向 Ceph 中存储数据呢&#xff1f;首先我们需要在 Ceph 中定义一个 Pool 资源池。Pool 是 Ceph 中存储 Object 对象抽象概念。我们可以将其理解为 Ceph 存储上划分的逻辑分区&#xff0c;Pool 由…

git使用-命令行+VS Code结合使用

一、Git常用命令 // 显示当分支的状态。它会列出已修改、已暂存和未跟踪的文件 git status// 列出本地仓库中所有的分支&#xff0c;其中会特殊显示当前所在分支 git branch// 在当前分支的基础上创建一个新的分支&#xff0c;并切换到这个新的分支上 git checkout -b 新分支…

Python创建Excel表和读取Excel表的基础操作

下载openpyxl第三方库 winr打开命令行输入cmd 这个如果不行可以试试其他方法&#xff0c;在运行Python代码的软件里也有直接下载的地方&#xff0c;可以上网搜索 创建Excel表 示例代码&#xff1a;最后要记得保存&#xff0c;可以加一句提示语句。 import openpyxl lst[100,…

文件IO(Ubuntu)

文件IO 目的 将数据写入文件中 与标准IO的区别 &#xff08;为什么要学习文件IO&#xff09; 标准IO只能操作普通文件和特殊的管道文件 文件IO能操作几乎所有的的文件 缓存区的目的 标准IO有缓存区 文件IO没有缓存区 根据右图描述 标准IO 文件IO buffer缓存区 有缓存区…

【SASS/SCSS(三)】样式的复用与动态计算(@mixin和@function)

目录 一、mixin 1、定义复用的样式代码&#xff0c;接受传参&#xff0c;搭配include使用。 位置传参 关键词传参 ...语法糖接受传入的任意参数 2、在mixin中使用content&#xff0c;获取外部对mixin的追加内容 二、function 三、字符串——值得注意的点 很多时候&#…

水域救援装备的详细简介_鼎跃安全

水域救援行动需要救援人员配备全面、专业的装备&#xff0c;以应对各种复杂的水域环境和救援任务。水域救援套装应运而生&#xff0c;它集合了水域救援所需的各类关键装备&#xff0c;为救援人员提供全方位的保护和辅助&#xff0c;确保数援行动的高效与安全。 水域救援头盔&am…