【进阶六】Python实现SDVRPTW常见求解算法——离散粒子群算法(DPSO)

news/2024/5/17 15:34:49

基于python语言,采用经典离散粒子群算法(DPSO)对 带硬时间窗的需求拆分车辆路径规划问题(SDVRPTW) 进行求解。

目录

  • 往期优质资源
  • 1. 适用场景
  • 2. 代码调整
    • 2.1 需求拆分
    • 2.2 需求拆分后的服务时长取值问题
  • 3. 求解结果
  • 4. 代码片段
  • 参考

往期优质资源


经过一年多的创作,目前已经成熟的代码列举如下,如有需求可私信联系,表明需要的 **问题与算法**,原创不宜,有偿获取。
VRP问题GAACOALNSDEDPSOQDPSOTSSA
CVRP
VRPTW
MDVRP
MDHVRP
MDHVRPTW
SDVRP
SDVRPTW

1. 适用场景

  • 求解SDVRPTW
  • 车辆类型单一
  • 车辆容量小于部分需求节点需求
  • 单一车辆基地
  • 带硬时间窗

2. 代码调整


2.1 需求拆分


与SDVRP问题相比,SDVRPTW问题不仅允许客户需求大于车辆载重,而且考虑了客户节点的时间窗约束。为了使得每个客户的需求得到满足,必须派遣一辆或多辆车辆在规定时间窗内对客户进行服务。对于需求节点的拆分,这里依然采取先验拆分策略,本文采用文献[1]提出的先验分割策略,表述如下:

(1)20/10/5/1拆分规则

  • m20 =max{ m ∈ Z + ∪ { 0 } ∣ 0.20 Q m < = D i m\in Z^+ \cup \{0\} | 0.20Qm <= D_i mZ+{0}∣0.20Qm<=Di }
  • m10 =max{ m ∈ Z + ∪ { 0 } ∣ 0.10 Q m < = D i − 0.20 Q m 20 m\in Z^+ \cup \{0\} | 0.10Qm <= D_i-0.20Qm_{20}~ mZ+{0}∣0.10Qm<=Di0.20Qm20  }
  • m5 =max{ m ∈ Z + ∪ { 0 } ∣ 0.05 Q m < = D i − 0.20 Q m 20 − 0.10 Q m 10 m\in Z^+ \cup \{0\} | 0.05Qm <= D_i-0.20Qm_{20}-0.10Qm_{10} mZ+{0}∣0.05Qm<=Di0.20Qm200.10Qm10 }
  • m1 =max{ m ∈ Z + ∪ { 0 } ∣ 0.01 Q m < = D i − 0.20 Q m 20 − 0.10 Q m 10 − 0.05 Q m 5 m\in Z^+ \cup \{0\} | 0.01Qm <= D_i-0.20Qm_{20}-0.10Qm_{10}-0.05Qm_{5} mZ+{0}∣0.01Qm<=Di0.20Qm200.10Qm100.05Qm5 }

(2)25/10/5/1拆分规则

  • m25 =max{ m ∈ Z + ∪ { 0 } ∣ 0.25 Q m < = D i m\in Z^+ \cup \{0\} | 0.25Qm <= D_i mZ+{0}∣0.25Qm<=Di }
  • m10 =max{ m ∈ Z + ∪ { 0 } ∣ 0.10 Q m < = D i − 0.25 Q m 25 m\in Z^+ \cup \{0\} | 0.10Qm <= D_i-0.25Qm_{25}~ mZ+{0}∣0.10Qm<=Di0.25Qm25  }
  • m5 =max{ m ∈ Z + ∪ { 0 } ∣ 0.05 Q m < = D i − 0.25 Q m 25 − 0.10 Q m 10 m\in Z^+ \cup \{0\} | 0.05Qm <= D_i-0.25Qm_{25}-0.10Qm_{10} mZ+{0}∣0.05Qm<=Di0.25Qm250.10Qm10 }
  • m1 =max{ m ∈ Z + ∪ { 0 } ∣ 0.01 Q m < = D i − 0.25 Q m 25 − 0.10 Q m 10 − 0.05 Q m 5 m\in Z^+ \cup \{0\} | 0.01Qm <= D_i-0.25Qm_{25}-0.10Qm_{10}-0.05Qm_{5} mZ+{0}∣0.01Qm<=Di0.25Qm250.10Qm100.05Qm5 }

在实现过程中,对于需求超过车辆容量的客户必须进行需求拆分,而对于未超过车辆容量的客户可以拆分也可以不拆分,这里设置了参数比例进行限制。

2.2 需求拆分后的服务时长取值问题


节点的服务时长会影响车辆的行进时间,进而会影响与节点时间窗的匹配问题。一般来说,节点的服务时长与需求量成正比关系,在进行节点需求拆分后,新节点的需求量降低,其服务时长理应也降低。但从标准数据集来看,各需求节点的服务时长均采用同一数值。因此本文在代码实现过程中也采用固定值,不考虑新节点服务时长的变化。当然,如有需要,也可以设置单位货物的服务时长,根据拆分后节点的具体需求量设置相应的服务时长。


3. 求解结果


(1)收敛曲线

在这里插入图片描述

(2)车辆路径

在这里插入图片描述

(3)输出内容

在这里插入图片描述


4. 代码片段


(1)数据结构

# 数据结构:解
class Sol():def __init__(self):self.obj=None # 目标函数值self.node_no_seq=[] # 解的编码self.route_list=[] # 解的解码self.timetable_list=[] # 车辆访问各点的时间self.route_distance_list = None
# 数据结构:需求节点
class Node():def __init__(self):self.id=0 # 节点idself.x_coord=0 # 节点平面横坐标self.y_coord=0  # 节点平面纵坐标self.demand=0 # 节点需求self.start_time=0 # 节点开始服务时间self.end_time=1440 # 节点结束服务时间self.service_time=0 # 单次服务时长self.vehicle_speed = 0 # 行驶速度
# 数据结构:车场节点
class Depot():def __init__(self):self.id=0 # 节点idself.x_coord=0 # 节点平面横坐标self.y_coord=0  # 节点平面纵坐标self.start_time=0 # 节点开始服务时间self.end_time=1440 # 节点结束服务时间self.v_speed = 0 # 行驶速度self.v_cap = 80 # 车辆容量
# 数据结构:全局参数
class Model():def __init__(self):self.best_sol=None # 全局最优解self.sol_list=[] # 解的集合self.demand_dict = {}  # 需求节点集合self.depot = None  # 车场节点集合self.demand_id_list = [] # 需求节点id集合self.distance_matrix = {}  # 距离矩阵self.time_matrix = {}  # 时间矩阵self.number_of_demands = 0 # 需求点数量self.demand_id_list_ = []  # 经先验需求分割后的节点集合self.demand_dict_ = {}  # 需求分割后的节点需求集合self.distance_matrix_ = {}  # 原始节点id间的距离矩阵self.time_matrix_ = {}  # 原始节点id间的时间矩阵self.mapping = {}  # 需求分割前后的节点对应关系self.split_rate = 0.5 # 控制需求分割的比例(需求超出车辆容量的除外)self.popsize = 100 # 种群规模self.pl=[] # 个体历史最优解self.pg=None # 种群历史最优解self.v=[] # 速度集合self.Vmax=5 # 最大移动速度self.w=0.8 # 惯性权重self.c1=2 # 信息启发式因子self.c2=2 # 信息启发式因子

(2)距离矩阵

# 读取csv文件
def readCSVFile(demand_file,depot_file,model):with open(demand_file,'r') as f:demand_reader=csv.DictReader(f)for row in demand_reader:node = Node()node.id = int(row['id'])node.x_coord = float(row['x_coord'])node.y_coord = float(row['y_coord'])node.demand = float(row['demand'])node.start_time=float(row['start_time'])node.end_time=float(row['end_time'])node.service_time=float(row['service_time'])model.demand_dict[node.id] = nodemodel.demand_id_list.append(node.id)model.number_of_demands=len(model.demand_id_list)with open(depot_file, 'r') as f:depot_reader = csv.DictReader(f)for row in depot_reader:depot = Depot()depot.id = row['id']depot.x_coord = float(row['x_coord'])depot.y_coord = float(row['y_coord'])depot.start_time=float(row['start_time'])depot.end_time=float(row['end_time'])depot.v_speed = float(row['v_speed'])depot.v_cap = float(row['v_cap'])model.depot = depot
# 初始化参数:计算距离矩阵时间矩阵
def calDistanceTimeMatrix(model):for i in range(len(model.demand_id_list)):from_node_id = model.demand_id_list[i]for j in range(len(model.demand_id_list)):to_node_id = model.demand_id_list[j]dist = math.sqrt((model.demand_dict[from_node_id].x_coord - model.demand_dict[to_node_id].x_coord) ** 2+ (model.demand_dict[from_node_id].y_coord - model.demand_dict[to_node_id].y_coord) ** 2)model.distance_matrix[from_node_id, to_node_id] = distmodel.time_matrix[from_node_id,to_node_id] = math.ceil(dist/model.depot.v_speed)dist = math.sqrt((model.demand_dict[from_node_id].x_coord - model.depot.x_coord) ** 2 +(model.demand_dict[from_node_id].y_coord - model.depot.y_coord) ** 2)model.distance_matrix[from_node_id, model.depot.id] = distmodel.distance_matrix[model.depot.id, from_node_id] = distmodel.time_matrix[from_node_id,model.depot.id] = math.ceil(dist/model.depot.v_speed)model.time_matrix[model.depot.id,from_node_id] = math.ceil(dist/model.depot.v_speed)

(3)邻域搜索

# 更新位置
def updatePosition(model):w=model.wc1=model.c1c2=model.c2pg = model.pgfor id,sol in enumerate(model.sol_list):x=sol.node_no_seqv=model.v[id]pl=model.pl[id].node_no_seqr1=random.random()r2=random.random()new_v=[]for i in range(model.number_of_demands):v_=w*v[i]+c1*r1*(pl[i]-x[i])+c2*r2*(pg[i]-x[i])if v_>0:new_v.append(min(v_,model.Vmax))else:new_v.append(max(v_,-model.Vmax))new_x=[min(int(x[i]+new_v[i]),model.number_of_demands-1) for i in range(model.number_of_demands) ]new_x=adjustRoutes(new_x,model)model.v[id]=new_vtimetable_list, new_obj, route_distance,route_list=calObj(new_x,model)if new_obj<model.pl[id].obj:model.pl[id].node_no_seq=copy.deepcopy(new_x)model.pl[id].obj=new_objmodel.pl[id].route_list=route_listmodel.pl[id].route_distance = route_distancemodel.pl[id].timetable_list = timetable_listif new_obj<model.best_sol.obj:model.best_sol.obj=copy.deepcopy(new_obj)model.best_sol.node_no_seq=copy.deepcopy(new_x)model.best_sol.route_list=copy.deepcopy(route_list)model.best_sol.route_distance = copy.deepcopy(route_distance)model.best_sol.timetable_list = copy.deepcopy(timetable_list)model.pg=copy.deepcopy(new_x)model.sol_list[id].node_no_seq = copy.deepcopy(new_x)model.sol_list[id].obj = copy.deepcopy(new_obj)model.sol_list[id].route_list = copy.deepcopy(route_list)model.sol_list[id].routes_distance = copy.deepcopy(route_distance)model.sol_list[id].timetable_list = copy.deepcopy(timetable_list)
# 调整不可行解
def adjustRoutes(node_no_seq,model):all_node_id_list=copy.deepcopy(model.demand_id_list_)repeat_node=[]for id,node_no in enumerate(node_no_seq):if node_no in all_node_id_list:all_node_id_list.remove(node_no)else:repeat_node.append(id)for i in range(len(repeat_node)):node_no_seq[repeat_node[i]]=all_node_id_list[i]return node_no_seq

参考

【1】 A novel approach to solve the split delivery vehicle routing problem


http://www.mrgr.cn/p/52001836

相关文章

python 爬虫

python 爬虫 1.开发工具 pycharm: https://pan.baidu.com/s/1s_bkgDT0QxNTQY07LnQRWQ?pwd=2dlb提取码:2dlb python3 VSCode 2.第一个爬虫的开发from urllib.request import urlopenurl = "http://www.baidu.com"resp = urlopen(url) #print(resp.read().decode(&q…

aardio 两行代码 优雅调用 libxl

废话不多说, 先给资源 https://files.cnblogs.com/files/blogs/762462/libxl.7z?t=1713539927&download=true 运行效果:文件存放路径:再上代码 import dotNet import consolexl = dotNet.load("libxl.net", "libxl.net.dll"); xl.import("libxl&…

c语言题目之求最大公约数

题目内容&#xff1a;求最大公约数 给定两个数&#xff0c;求这两个数的最大公约数 例如&#xff1a; 输入&#xff1a;20 40 输出&#xff1a;20 什么叫最大公约数&#xff1f; 方法分析&#xff1a; 提示&#xff1a;这里我们用辗转相除法&#xff1a; 例如&#xff1a;输…

信号处理相关知识

一&#xff1a; 1.序列——三种典型序列通过matlab绘图即可 2.数字信号的自变量一定是整数&#xff0c;幅度上取值是有限的状态&#xff08;不一定是整数&#xff09;。 3.抽取和插值 4.模拟正弦信号sin(wt):w是角频率&#xff0c;单位rad/s,f是频率w/2Π。 5.假设用采样周…

如何在Windows 10中启用和使用上帝模式,这里有详细步骤

序言 上帝模式&#xff08;God Mode&#xff09;是一个特殊的文件夹&#xff0c;只在一个窗口中显示所有可用的操作设置。它可以节省搜索命令的时间&#xff0c;而无需知道通过“开始”菜单或“控制面板”查找命令的步骤。上帝模式默认情况下是隐藏的&#xff0c;所以我们需要…

Godaddy ssl证书配置到nginx

godaddy官网:https://www.godaddy.com/ 由于godaddy下载的证书没有key文件,保存官方给的key文件nginx报错,所以先自己生成,重新在godaddy上申请验证.csr文件openssl req -new -newkey rsa:2048 -nodes -keyout domain.key -out domain.csr生成过程会询问几个常见问题,比如Ci…

1.微服务介绍

完整的微服务架构图 注册中心 配置中心 服务集群 服务网关 分布式缓存 分布式搜索 数据库集群 消息队列 分布式日志服务 系统监控链路追踪 Jenkins docker k8s 技术栈 微服务治理&#xff1a; 注册发现、远程调用、负载均衡、配置管理、网关路由、系统保护、流量…

华为云服务镜像手动更换

操作步骤&#xff1a; 1、进入华为云首页点击云容器引擎CCE&#xff1b; 2、选择你所要更换镜像的环境【这里以dev环境演示】&#xff1b; 3、点击dev环境后选择顶部的命名空间&#xff0c;点击【工作负载】中右侧栏的【升级】按钮&#xff1b; 4、点【更换镜像】选择你在test…

「探索C语言内存:动态内存管理解析」

&#x1f320;先赞后看&#xff0c;不足指正!&#x1f320; &#x1f388;这将对我有很大的帮助&#xff01;&#x1f388; &#x1f4dd;所属专栏&#xff1a;C语言知识 &#x1f4dd;阿哇旭的主页&#xff1a;Awas-Home page 目录 引言 1. 静态内存 2. 动态内存 2.1 动态内…

【DL水记】循环神经网络RNN的前世今生,Transformer的崛起,Mamba模型

文章目录 RNN网络简介传统RNN网络结构RNN的分类 长-短期记忆网络 (LSTM)GRU网络横空出世的Transformer网络Self-AttentionVisionTransformer Mamba模型Reference: RNN网络简介 “当人类接触新事物时&#xff0c;他们不会从头开始思考。就像你在阅读这篇文章时&#xff0c;你会根…

【读点论文】YOLOX: Exceeding YOLO Series in 2021,无锚框单阶段目标检测方案,解耦检测头的分类和回归分支,优化标签分配策略

YOLOX: Exceeding YOLO Series in 2021 Abstract 在本报告中&#xff0c;我们介绍了YOLO系列的一些经验改进&#xff0c;形成了一种新的高性能探测器—YOLOX。我们将YOLO检测器切换到无锚方式&#xff0c;并进行其他先进的检测技术&#xff0c;即去耦头和领先的标签分配策略S…

常用UI组件

一、文本组件 1.1 概述 Text为文本组件&#xff0c;用于显示文字内容 1.2 参数 Text组件的参数类型为string | Resource Entry Component struct Index {build() {Column({space : 50}) {Text(你好).fontSize(50)}.width(100%).height(100%).justifyContent(FlexAlign.Cent…

【Entity Framework】闲话EF中批量配置

【Entity Framework】闲话EF中批量配置 文章目录 【Entity Framework】闲话EF中批量配置一、概述二、OnModelCreating中的批量配置元数据API的缺点 三、预先约定配置忽略类型默认类型映射预先约定配置的限制约定添加新约定替换现有约定约定实现注意事项 四、何时使用每种方法进…

Rust实现hotkey

最近想写一个快捷启动工具来满足自己的需求,刚好用自己最喜欢的 Rust 来实现实现方法 文档: global_hotkey 具体代码 use global_hotkey::{hotkey::{Code, HotKey, Modifiers},GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState, }; use winit::event_loop::{ControlFlow,…

2024面试软件测试,常见的面试题(上)

一、综合素质 1、自我介绍 面试官您好&#xff0c;我叫XXX&#xff0c;一直从事车载软件测试&#xff0c;负责最多的是中控方面。 以下是我的一些优势&#xff1a; 车载的测试流程我是熟练掌握的&#xff0c;且能够独立编写测试用例。 平时BUG提交会使用到Jira&#xff0c;类似…

海外云手机为什么适合社媒运营?

如今&#xff0c;社媒营销如果做得好&#xff0c;引流效果好的账号&#xff0c;可以用来带货变现&#xff0c;而外贸、品牌出海也同样都在做社媒营销&#xff0c;Tik Tok、facebook、ins等热门的海外社媒平台都是行业密切关注的&#xff0c;必要的时候&#xff0c;大家会使用海…

高级IO和5种IO模型

目录 1. 高级IO1.1 IO的基本概念1.2 OS如何得知外设当中有数据可读取1.3 OS如何处理从网卡中读取到的数据包1.4 IO的步骤 2. 五种IO模型2.1 利用钓鱼来理解2.2 阻塞IO2.3 非阻塞IO2.4 信号驱动IO2.5 IO多路转接2.6 异步IO 3. 高级IO的概念3.1 同步通信 VS 异步通信3.2 阻塞 VS …

FineReport11 报表技巧02- 实现类Excel表头筛选功能

背景: 在报表开发中,有的需求方用习惯Excel的表头筛选时,就不太习惯帆软的特意点击报表控件进行筛选,希望报表筛选方式可以类似Excel那种直接在表头进行筛选的功能 最终效果如下:实现步骤: 1.1、数据集准备 产品信息表: SELECT 客户,产品,数量,cast(下单时间 as date) a…

项目冲刺

项目冲刺汇总 第一天 第二天 会议图片第三天 会议图片第四天 会议图片第五天 会议图片第六天 会议图片第七天 会议图片燃尽图

正则表达式(Regular Expression)

正则表达式很重要&#xff0c;是一个合格攻城狮的必备利器&#xff0c;必须要学会&#xff01;&#xff01;&#xff01; &#xff08;参考视频&#xff09;10分钟快速掌握正则表达式&#xff08;奇乐编程学院&#xff09;https://www.bilibili.com/video/BV1da4y1p7iZ在线测试…