论文复现丨带时间窗和服务顺序的多车辆路径问题:联合优化遗传算法

news2024/11/15 20:09:54


路径优化系列文章:

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

问题描述

某区域内有1个配送中心(配送中心集合记为J = {0}),分别用m种车型为n个顾客(顾客集合记为 I = {1, 2*, . . . , n})提供m种不同类型的服务(服务需求类型集合记为K* = {1, 2*,* · · · , m}),每种类型的车辆只能提供单一类型的服务,假设:

(1)各种类型的车辆均从配送中心出发,完成任务后仍回到原配送中心;

(2)每个顾客的一种需求只需要被同类型车辆服务一次;

(3)每条路径上的顾客总需求量不能超过车辆的最大服务能力;

(4)每辆车的总行驶时间不能超过规定的最长行驶时间;

(5)每个顾客的第1种需求对应的时间窗为软时间窗,服务车辆早到或晚到会产生等待或惩罚费用;

(6)具有多种服务需求的顾客,其各类需求的服务顺序为1*,* 2*,* · · · , m,即同一顾客的第k类服务完成时间必须早于第k + 1类服务的开始时间,且时间间隔不能超过最大允许时间间隔SLk(服务水平。

简单来说:客户点有多个服务需求,两个服务时间点差距必须在一定范围内,其余同一般车辆路径问题一样。文献的客户点有配送需求,安装需求(部分点)。

数学模型

文献的模型:

第一部分是车辆固定成本,第二部是行驶成本,第三部分是时间窗成本。

数据:

包含参考文献参考数据和rc101到rc108成本:

文献参考数据

rc数据:

其中论文参考数据没有时间窗(可以自行设计),解码时不计算,rc数据无安装点,按照文献任意生成40个。

代码运行环境
windows系统,python3.6.0,第三方库及版本号如下:

numpy==1.18.5
matplotlib==3.2.1

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

  • 1、代码运行环境说明

  • 2、第三方库安装方法

编码解码

1、编码

随机打乱配送点和安装点即可得到配送路径编码和安装路径编码。

2、配送路径解码

依次遍历配送路径,载重约束下车辆尽可能服务更多点:

step1:初始只有一辆车,载重为0,遍历路径第一个点,更新载重,更新车辆路径;

step2:不断遍历路径的点,更新载重和车辆路径,遍历到某点不满足载重时转入step3;,否则遍历完所有点结束;

step3:新加入车辆,载重更新为该点的需求量,新车辆路径加入该点。

核心代码如下:

    while road:                                  # 当路径还有点未分配给车
        DE_idx.append(road[0])                   # 每次车辆路径加入路径第一个点
        if sum(np.array(self.DE)[DE_idx])<=self.load:  
            road.pop(0)                          # 如果满足载重约束,删除路径第一个点          
        else:
            road_car.append(DE_idx[:-1])         # 如果不满足,截取上一个车辆路径
            DE_idx = []                          # 新车辆路径从空开始
    road_car.append(DE_idx)                      # 循环完成添加最后一辆车辆路径

得到各车辆的路径后,计算成本比较容易,路径数就是车辆数,任意2点距离除速度得到时间,累积时间就可以判断是否违反时间窗:

def caculate(self,road_car,signal):
        t_arrive = []
        t_a = [0 for w in self.AZ]                  # 初始安装点的配送时间为0
        z = len(road_car)
        for rc in road_car:                         # 每辆车的路径
            t = 0
            beg_ = 0                                # 从中心0开始
            for r in rc + [0]:                      # 最后回到中心0
                dis = np.sqrt((self.XY[r][0] - self.XY[beg_][0])**2 + (self.XY[r][1] - self.XY[beg_][1])**2)
                t += dis/self.v                     # 计算到达时间
                if r in self.AZ:                    # 如果点属于安装路径
                    idx = self.AZ.index(r)          # 找到对应点在安装路径编码的位置
                    t_a[idx] = t                    # 更新安装点到达时间
                t_arrive.append(t)                  # 更新每个点到达时间(包括回到中心点)
                beg_ = r
        w = self.gk*z + self.ck*sum(t_arrive)       # 计算不包含时间窗的成本
        if self.WD and signal:                      # 如果时间窗存在且需要计算(安装路径时不需要)
            c = 0
            u = 0
            for rc in road_car:                     # 路径成本
                for r in rc + [0]:
                    win_left = self.WD[r][0]        # 左时间窗
                    win_right = self.WD[r][1]       # 右时间窗
                    if t_arrive[c] < win_left:      # 时间窗成本计算,下同
                        u += 2*(win_left-t_arrive[c])
                    if t_arrive[c] > win_right:
                        u += 2*(t_arrive[c] - win_right) 
                    c += 0
            w += u                                  # 成本更新
        return w,t_a

当有时间窗数据且需要计算才会计算时间窗成本(安装点路径不需要计算) ,t_a是为了下面的安装路径解码。

3、安装路径解码

依次遍历安装路径,安装路径的点必须和配送时间点在一定范围内(2种情况:早于安装时间;晚于配送时间时间时在允许范围内到达),否则该点加入新车:

step1:初始只有一辆车,载重为0,遍历安装路径第一个点,更新时间(安装车到达时间和配送车到达时间的最大值),更新车辆路径;

step2:不断遍历路径的点,更新时间和车辆路径,遍历到某点时间不满足间隔约束时转入step3;,否则遍历完所有点结束;

step3:新加入车辆,时间更新为中心到该点的时间,新车辆路径加入该点。

核心代码:

for i in range(len(road_car)):         # 遍历目前的安装车
    if i==0:                           # 初始从配送中心出发
        beg_ = 0
    else:
        beg_ = road_car[i][-1]         # 否则从某辆车的最后一个点出发
    dis = np.sqrt((self.XY[r][0] - self.XY[beg_][0])**2 + (self.XY[r][1] - self.XY[beg_][1])**2)
    t = dis/self.v + ta[i]             # 计算到达时间
    if t - t_arrive <= self.slk:       # 如果到达时间在可接受范围
        road_car[i].append(r)          # 车辆加入该点
        ta[i] = max(t, t_arrive)       # 更新该点的完工时间(安装到达时间和配送时间最大值)
        signal = 1
        break
if signal == 0:                        # 如果所有车都没加入点
    beg_ = 0
    dis = np.sqrt((self.XY[r][0] - self.XY[beg_][0])**2 + (self.XY[r][1] - self.XY[beg_][1])**2)
    road_car.append([])               # 添加新车
    t = dis/self.v
    ta.append(max(t, t_arrive))       # 更新该点的完工时间
    road_car[-1].append(r)            # 新车路径加入点

成本计算同上。

算法改进

1、算法步骤

轮盘赌选择,概念可以自行查阅,用np.random.choice实现:

def select(self,pop,pop1,fit):          # 轮盘赌选择
        fit=np.array(fit)
        idx=np.random.choice(np.arange(self.pop_size),size=self.pop_size,replace=True,
                             p=fit/fit.sum())
        return pop[idx],pop1[idx]

idx是轮盘赌选择得到的索引,因为文献存在配送路径和安装路径,返回2个种群。

次序交叉:

任意生成2点,固定2点之间的基因和位置,处理其余冲突基因再重新拼接。

如B处理冲突的1,4,3剩余[2,7,5,6,8],[1,4,3]左拼接[2,7],右拼接[5,6,8]得到子代A,子代B同理。

代码:

def crosss(self, a, b):                    # 次序交叉
    loc = random.sample(range(len(a)), 2)  # 生成2个位置
    loc.sort()                             # 升序
    id1, id2 = loc[0],loc[1]               # 取对应位置点
    change_a = a[id1:id2]                  # 截取交换位置          
    change_b = b[id1:id2]                  # 截取交换位置

    for ca in change_a:                    # 父代b移除a交换的对应基因
        b.remove(ca)
    a1 = b[:id1] + change_a + b[id1:]      # b剩余基因和交换基因得到子代a1

    for cb in change_b:                    # 父代a移除b交换的对应基因
        a.remove(cb)
    b1 = a[:id1] + change_b + a[id1:]      # a剩余基因和交换基因得到子代b1
    return a1, b1                         

变异是交换一个编码任意2个位置的基因:

def mul(self,a):
    loc = random.sample(range(len(a)), 2)  # 生成2个位置
    a[loc[0]], a[loc[1]] = a[loc[1]], a[loc[0]] # 对应基因交换
    return a

保留top N个体,比较容易,每次迭代合并父代和子代,保留最优秀的前N个个体:

核心代码:

T_r, T_rz =np.vstack((T_road,T_road1)),np.vstack((T_road_az,T_road_az1))  # 合并父代子代路径
ans = answer + answer1                             # 合并父代子代目标

index_sort=np.array(ans).argsort()                 # 目标最小到大的索引
T_road, T_road_az = T_r[index_sort][0:self.pop_size],  T_rz[index_sort][0:self.pop_size] # top N个体
answer = np.array(ans)[index_sort][0:self.pop_size].tolist() # 对应目标

运行结果

主函数

设计主函数如下:

import data
import numpy as np
from decode import de
import random
from ga_combine import ga_c

data_ = 'RC101'          # 可选择101到108,运行rc数据时记得屏蔽data_ = 0
data_ = 0                # 运行论文数据

if data_:
    XY, DE, WD = data.read_rc(data_)
    AZ = random.sample(range(1, len(DE)), 40) # 生成40个安装点
else:
    XY, DE, AZ = data.read()
    
gk = 20     # 单个车辆固定费用
ck = 1      # 单位距离运行成本
v = 1       # 车辆速度
if data_:        # rc系列数据时
    load = 1000  # 载重
    slk = 300    # 允许安装时间和配送时间间隔
else:
    load = 15    # 载重
    slk = 40     # 允许安装时间和配送时间间隔
    WD = []      # 论文数据没时间窗,可自行设计

generation, popsize, cr, mu = 20, 40, 1, 1          # 迭代次数,种群规模,交叉概率,变异概率
d = de(gk, ck, v, load, XY, DE, AZ,slk,WD)          # 解码方法
gc = ga_c(generation, popsize, cr, mu, d)           # 遗传方法
road, road_z, result = gc.total(len(DE)-1, len(AZ)) # 算法结果

road,road_car = d.creat(road) 
w1,t_a = d.caculate(road_car,1)
road_car_az = d.caculate_az(road_z,t_a)
w2,t_a = d.caculate(road_car_az ,[])

print('\n配送编码:',road)
print('车辆配送路径:',road_car)
print('\n安装编码',road_z)
print('车辆安装编码:',road_car_az)
print(f'成本验证:{w1+w2:.2f}')

d.draw(road_car, road_car_az, w1, w2,data_)  # 路径图
d.draw_change(result)                        # 迭代图

运行结果

论文数据20次结果:

路径图

迭代图

rc101数据20次结果

路径图

迭代图

小结

  • 本推文基本对参考论文进行复现,进行了论文数据和rc101到rc108的测试,希望有借鉴意义。excel数据和算法代码参数皆可修改(修改时注意不要改变excel数据的布局)。

  • 参考文献:带时间窗和服务顺序约束的多需求车辆路径问题 (李珍萍 张煜炜)

代码

为了方便和便于修改和测试,把代码在4个py文件里,pa.py是rc101-108的一个简单爬虫程序。

演示视频:

论文复现丨带时间窗和服务顺序的多车辆路径问题:联合优化遗传算法

完整算法+数据:

可加微信:diligent-1618,请备注:学校-专业-昵称。

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

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

相关文章

Linux命令行 复制模式/扩展模式 调用系统功能切换

问题背景 公司软件需要从window 适配国产操作系统&#xff0c;目前使用wine方案。在我们软件有个切换屏幕模式的功能&#xff0c;需要支持用户在我们软件内&#xff0c;切换复制模式/扩展模式。 在linux 下 uos/deepin 等系统。如果要从复制模式设置为扩展模式使用命令行时&a…

零基础入门转录组数据分析——机器学习算法之SVM-RFE(筛选特征基因)

零基础入门转录组数据分析——机器学习算法之SVM-RFE&#xff08;筛选特征基因&#xff09; 目录 零基础入门转录组数据分析——机器学习算法之SVM-RFE&#xff08;筛选特征基因&#xff09;1. SVM-RFE基础知识2. SVM-RFE&#xff08;Rstudio&#xff09;——代码实操2. 1 数据…

从零到一:用Go语言构建你的第一个Web服务

使用Go语言从零开始搭建一个Web服务&#xff0c;包括环境搭建、路由处理、中间件使用、JSON和表单数据处理等关键步骤&#xff0c;提供丰富的代码示例。 关注TechLead&#xff0c;复旦博士&#xff0c;分享云服务领域全维度开发技术。拥有10年互联网服务架构、AI产品研发经验、…

【Git-驯化】一文搞懂git中rm命令的使用技巧

【Git-驯化】一文搞懂git中rm命令的使用技巧 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 免费获取相关内容文档关注&#xff1a;微信公…

Day12--Servlet实现前后端交互(案例:学生信息管理系统登录页面)

&#xff08;在一个完整的项目架构中&#xff0c;servlet的角色和位置&#xff09; Servlet、GenericServlet和HttpServlet三者之间的关系是Java Web开发中的一个重要概念&#xff0c;它们共同构成了基于Java的服务器端程序的基础。以下是具体分析&#xff1a; 1. Servlet接口…

Windows下nmap命令及Zenmap工具的使用方法

一、Nmap简介 nmap是一个网络连接端扫描软件&#xff0c;用来扫描网上电脑开放的网络连接端。确定哪些服务运行在哪些连接端&#xff0c;并且推断计算机运行哪个操作系统&#xff08;这是亦称 fingerprinting&#xff09;。它是网络管理员必用的软件之一&#xff0c;以及用以评…

算法-DFS-树形DP

题目一 解题思路 比较标准的深搜&#xff0c;难点主要在题目的理解&#xff0c;通俗的说就是要找到一个树结构中的点&#xff0c;使之在去掉该点后剩余数的结构最均等&#xff08;剩余连接节点的最大值最小&#xff09;。 无向图邻接表 使用代码实现需要一个数组存储数值、一…

速看!2024年5月软考通过率解析

根据湖南省工业和信息化厅最新发布的《2024年上半年软考湖南考区工作总结报告》及《考试安全顺利完成的通报》&#xff0c;我们了解到湖南地区在2024年上半年度的软件与信息技术专业人才考试&#xff08;简称“软考”&#xff09;中&#xff0c;报名人数达到了13,762人&#xf…

无人机1公里WiFi图传遥控模组,飞睿智能无延迟传输方案,高效稳定告别卡顿

在信息众多的时代&#xff0c;我们享受着科技带来的便利&#xff0c;同时也期待着更多前沿技术的出现。今天&#xff0c;就让我们一起走进一个充满神秘与可能性的领域——飞睿智能1公里WiFi图传遥控模组。这个看似简单的设备&#xff0c;却蕴含着巨大的能量&#xff0c;它正在悄…

深度学习-感知机

目录 感知机训练感知机感知机模型感知机学习算法 收敛定理XOR问题总结 多层感知机学习XOR隐藏层单隐藏层---单分类激活函数Sigmoid激活函数Tanh 激活函数ReLU 激活函数 多类分类---单隐藏层多类分类---多隐藏层总结 多层感知机从零开始多层感知机的简洁实现总结 感知机 给定输…

智慧通信|IEEE Trans. Commun. 论文解读:延迟敏感的能量收集无线传感器的最佳调度、结构特性和近似分析

原文信息 Sharma, Nikhilesh, Nicholas Mastronarde, and Jacob Chakareski. “Delay-sensitive energy-harvesting wireless sensors: Optimal scheduling, structural properties, and approximation analysis.” IEEE Transactions on Communications 68.4 (2019): 2509-25…

OZON如何查询销量,OZON查销量哪里可以看

在竞争激烈的电商市场中&#xff0c;了解商品销量是每位卖家优化销售策略、提升竞争力的关键。作为俄罗斯领先的跨境电商平台&#xff0c;Ozon为卖家提供了丰富的数据支持&#xff0c;帮助卖家更好地掌握市场动态。然而&#xff0c;对于新手卖家来说&#xff0c;如何在Ozon上查…

1、爬⾍概述

1. 什么是爬虫&#xff1f; 爬虫&#xff08;Web Crawler&#xff09;是一种通过编写程序自动访问并提取互联网上数据的技术。爬虫可以帮助我们在浏览网页时自动收集和保存一些有用的数据&#xff0c;例如图片、视频和文本信息。简单来说&#xff0c;爬虫就是自动化的浏览器。…

InsightFace 人脸识别算法实现过程解析

最近研究了一下人脸识别算法&#xff0c;初步实现了基础的人脸识别。 源码github下载地址&#xff1a;insightface 第一步 解压源码配置环境 1、使用conda虚拟环境创建insightface环境 conda create -n insightface python3.8创建环境完成后&#xff0c;激活环境 conda ac…

手把手教你如何在宝塔上添加可道云登录页面的ICP备案信息,别跟权威开玩笑。

如何在宝塔上添加可道云登录页面的ICP备案信息 事情的原由来我们开始吧首先登录你的宝塔页面双击打开index.php文件保存退出即可 感谢大佬&#xff0c;希望对被查到的朋友有所帮助&#xff01; 事情的原由 今天突然收到腾讯云发来的一封Email&#xff0c;说我需要整改我的网站…

如何在职场上生存,送你3条秘技

洞悉本质才能方向明确&#xff0c;掌握方法才能事半功倍。 下面这3条职场生存的秘技&#xff0c;都是“过来人”的经验之谈&#xff0c;不管在哪里工作&#xff0c;都能管中窥豹、可见一斑&#xff0c;实在是值得深刻领悟。 01 你和领导的本质关系是工作关系 你有价值&#xff…

嵌入式开发服务器与客户端交互 日志2024/7/31

嵌入式开发服务器与客户端交互 客户端 网页 操作 请求相关代码: 这里为了适配 低版本浏览器 用的不是fetch 当然用fetch更好 var curUlr window.location.href; //获取当前网页地址var newURL curUlr.lastIndexOf("/");//截取到最后一个斜杠索引var pathUrl…

Python:如何实现对表格的自动化

前情提要&#xff1a;需要有openpyxl哦 如果没有请参考上一篇文章 http://t.csdnimg.cn/fjbLJ 先介绍一下对表格的基本操作 首先创立一个 transactions.xlsx 基本操作&#xff1a;获取表格&#xff0c;获取值 import openpyxl as xl # 这个as 单纯简化 相当于别名 wbxl.load_…

02 I/O多路复用---进程的聊天

服务器同时和很多客户端连在一起 管道的read&#xff0c;总是能读出来

mysql逻辑架构与sql执行过程

目录 1.背景 2.mysql逻辑架构图 3.逻辑架构解读 第一层:连接层 第二层:服务层 1.Management Serveices & Utilities 2.SQL Interface:SQL接口 3.Parser:解析器 4.Optimizer:查询优化器 5.Caches 和 Buffers:查询缓存组件 第三层:存储引擎层 第四层:数据存储层 …