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

基于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 # 节点id
        self.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 # 节点id
        self.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] = node
            model.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] = dist
            model.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] = dist
        model.distance_matrix[model.depot.id, from_node_id] = dist
        model.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.w
    c1=model.c1
    c2=model.c2
    pg = model.pg
    for id,sol in enumerate(model.sol_list):
        x=sol.node_no_seq
        v=model.v[id]
        pl=model.pl[id].node_no_seq
        r1=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_v

        timetable_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_obj
            model.pl[id].route_list=route_list
            model.pl[id].route_distance = route_distance
            model.pl[id].timetable_list = timetable_list
        if 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.mfbz.cn/a/554482.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

.netcore+vue新生分班系统的设计与实现

.netcore vue新生分班系统的设计与实现说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于.net core架构和mysql数据库vue 东北石油大学新生分班系统的设计与实现 功能模块&#xff1a; 登录 注册学生 忘记密码 系统首顶 个…

fatal error C1001: An internal error has occurred in the compiler

VS2008驱动项目A&#xff0c;集成一个Wzarid生成的驱动LIB项目B&#xff0c;在编译64位驱动时,出现以下错误&#xff1a; 1>------ Build started: Project: xxxx, Configuration: Release x64 ------ 1>Linking... 1>fatal error C1001: An internal error has occu…

AI时代下,普通人能怎么做?

AI玩法千千万&#xff0c;你已经知道了多少呢&#xff1f;是否已经实践起来&#xff1f; 大家好&#xff0c;我是程序员影子 | 全网同名 一名致力于帮助更多朋友快速入门编程的程序猿 今天&#xff0c;我将以小白入门的视角带着大家了解一下目前火热的AI实践玩法&#xff1b…

SQL --索引

索引 INDEX 伪列 伪装起来的列&#xff0c;不容易被看见&#xff0c;要特意查询才能看见 ROWNUM&#xff1a; 是对查询结果自动生成的一组连续的自然数序号。 SELECT emp.*,ROWNUM FROM emp例题&#xff1a;查询emp表中&#xff0c;前三个员工 SELECT * FROM * from emp w…

工业控制(ICS)---MMS

MMS 工控领域的TCP协议&#xff0c;有时wireshark会将response包解析为tcp协议&#xff0c;影响做题&#xff0c;如果筛选mms时出现连续request包&#xff0c;考虑wireshark解析错误&#xff0c;将筛选条件删除手动看一下 initiate&#xff08;可以理解为握手&#xff09; i…

QQ浏览器模仿Arc,推垂直工作栏引领新体验潮流|TodayAI

之前在硅谷大受欢迎的AI浏览器Arc一经推出就立即引起了广泛关注&#xff0c;Arc自称不仅仅是一款浏览器&#xff0c;而且还是一个“与互联网同规模的平台”。如今&#xff0c;中国的QQ浏览器也想借Arc的热潮之势&#xff0c;同样采用了类似Arc的垂直工作栏&#xff0c;声称能够…

【总结】jdk安装配置后,执行报错java: error while loading shared libraries: libjli.so

目录 问题现象排查分析解决方法 问题现象 安装jdk后&#xff0c;配置好了环境变量&#xff0c;但执行java -vesion命令时&#xff0c;报错。 java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directory 看起来这个…

就业分析丨云计算数通双认证学员,入职海外年薪50W

扫码联系誉天猎头部&#xff0c;可享高薪岗位内推、职业规划岗前测评等服务 誉天&#xff0c;我的职业启航之地 大家好&#xff0c;我是誉天学员万*,回想起那段为梦想而奋斗的日子&#xff0c;我的心中充满了感慨。誉天在行业内一直深受好评&#xff0c;在我心中播下了技能的种…

14.多态(多态的构成条件、虚函数的重写、抽象类也就是纯虚函数的类、虚函数表、单继承和多继承的虚函数表)

1.多态的概念 ​ 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 举个例子&#xff1a;比如买票这个行为&#xff0c;当普通人买票时&#xff0c;是全价买票&#xff1b;…

java动态代理--JDK代理

1.概述 JDK动态代理&#xff1a;只能代理实现了接口的类&#xff0c;代理对象是实现了目标对象所有接口的代理类 使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来创建代理对象&#xff0c;工作通过反射机制完成。 2.实现接口InvocationHandler …

目标检测——防护装备数据集

一、重要性及意义 防护装备中的头盔和背心检测具有至关重要的重要性和深远的意义&#xff0c;主要体现在以下几个方面&#xff1a; 首先&#xff0c;它们对于保护工作人员的人身安全起着至关重要的作用。在各类工作环境中&#xff0c;尤其是那些涉及高空作业、机械操作或交通…

windows10 VS2017 grpc1.48.0环境配置

本文介绍在Windows10 下使用Visual Studio 2017编译gRPC 1.48.0并配置开发环境&#xff0c;以及开发、配置一个简单的c服务端以及客户端。&#xff08;过程令人头疼&#xff0c;参阅了大量博客&#xff0c;实际操作都存在问题&#xff0c;整理一下&#xff0c;希望对后来者有帮…

每日一练

这是一道牛客的dd爱框框的题 题目解析: 就是求大于x的最短子序列 我的思路:是滑动窗口 public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextInt()) { // 注意 while 处理多个 caseint n in.…

基于springboot实现信息化在线教学平台设计【项目源码+论文说明】计算机毕业设计

基于springboot实现信息化在线教学平台设计演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了信息化在线教学平台的开发全过程。通过分析信息化在线教学平台管理的不足&#xff0c;创建了一个计算机管理信息…

时序分解 | Matlab实现TVF-EMD时变滤波器的经验模态分解信号分量可视化

时序分解 | Matlab实现TVF-EMD时变滤波器的经验模态分解信号分量可视化 目录 时序分解 | Matlab实现TVF-EMD时变滤波器的经验模态分解信号分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现TVF-EMD(时变滤波器的经验模态分解)可直接替换 Matlab语言 1.…

2024年思维100春季线上赛倒计时2天,快来做思维100历年真题700道

今天是2024年4月18日&#xff0c;距离2024年春季思维100活动第一阶段的线上比赛4月20日还有2天。我们来从历年的思维100真题中来分析和推测&#xff0c;把历年真题和背后的知识点吃透了&#xff0c;举一反三&#xff0c;并建立自己的解题思路和技巧。从而提高思维100的考试成绩…

OSPF星型拓扑和MGRE全连改

一&#xff0c;拓扑 二&#xff0c;要求 1&#xff0c;R6为ISP只能配置IP地址&#xff0c;R1-R5的环回为私有网段 2&#xff0c;R1/4/5为全连的MGRE结构&#xff0c;R1/2/3为星型的拓扑结构&#xff0c; 3&#xff0c;R1为中心站点所有私有网段可以互相通讯&#xff0c;私有网段…

JavaWeb--05Vue项目简介

Vue项目简介 1 创建vue项目2 Vue项目目录结构3 运行Vue项目3 Vue项目开发流程 1 创建vue项目 环境准备好了&#xff0c;接下来我们需要通过Vue-cli创建一个vue项目&#xff0c;然后再学习一下vue项目的目录结构。Vue-cli提供了如下2种方式创建vue项目: 命令行&#xff1a;直接…

基于大数据的手机销售数据分析可视化系统,爬取京东和淘宝的的手机商品数据进行分析,Flask,Python,数据可视化

介绍 该系统主要是通过爬取京东和淘宝的的手机商品数据进行分析。爬虫python脚本通过打开浏览器授权登录后按照搜索“手机”关键字后出现的商品列表进行爬取&#xff0c;获取标题名&#xff0c;解析付款人数&#xff0c;品牌&#xff0c;评论人数&#xff0c;发货地&#xff0…

集合-CollectionListSet

Collection体系的特点、使用场景总结 如果希望元素可以重复&#xff0c;又有索引&#xff0c;索引查询要快? 用ArrayList集合, 基于数组的。(用的最多) 如果希望元素可以重复&#xff0c;又有索引&#xff0c;增删首尾操作快? 用LinkedList集合, 基于链表的。 如果希望增…