【进阶六】Python实现SDVRPTW(需求拆分)常见求解算法——禁忌搜索+模拟退火算法(TS+SA)

基于python语言,采用经典禁忌搜索(TS)+模拟退火(SA)对 带硬时间窗的需求拆分车辆路径规划问题(SDVRPTW) 进行求解。

目录

  • 往期优质资源
  • 1. 适用场景
  • 2. 代码调整
    • 2.1 需求拆分
    • 2.2 需求拆分后的服务时长取值问题
  • 3. 求解结果
    • 3.1 TS
    • 3.2 SA
  • 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. 求解结果


3.1 TS


(1)收敛曲线
在这里插入图片描述
(2)车辆路径
在这里插入图片描述

(3)输出内容
在这里插入图片描述

3.2 SA


(1)收敛曲线
在这里插入图片描述

(2)车辆路径
在这里插入图片描述

(3)输出内容
在这里插入图片描述


4. 代码片段


(1)数据结构

import math
import random
import numpy as np
import copy
import xlsxwriter
import matplotlib.pyplot as plt
import csv
import time
# 数据结构:解
class Sol():
    def __init__(self):
        self.obj=None # 目标函数值
        self.node_no_seq=[] # 解的编码
        self.route_list=[] # 解的解码
        self.timetable_list=[] # 车辆访问各点的时间
        self.route_distance_list = None
        self.action_id = None  # 对应的算子id
# 数据结构:需求节点
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.split_rate = 0.5 # 控制需求分割的比例(需求超出车辆容量的除外)
        self.tabu_list=None # 禁忌表
        self.TL=30 # 禁忌长度

(2)距离矩阵

# 初始化参数
def cal_distance_matrix(model):
    for i in model.demand_id_list:
        for j in model.demand_id_list:
            d=math.sqrt((model.demand_dict[i].x_coord-model.demand_dict[j].x_coord)**2+
                        (model.demand_dict[i].y_coord-model.demand_dict[j].y_coord)**2)
            model.distance_matrix[i,j]=max(d,0.0001) if i != j else d
        dist = math.sqrt((model.demand_dict[i].x_coord - model.depot.x_coord) ** 2 + (model.demand_dict[i].y_coord - model.depot.y_coord) ** 2)
        model.distance_matrix[i, model.depot.id] = dist
        model.distance_matrix[model.depot.id, i] = dist

(3)邻域

# 构造初始解
def genInitialSol(node_no_seq):
    node_no_seq=copy.deepcopy(node_no_seq)
    random.shuffle(node_no_seq)
    return node_no_seq
# 定义邻域算子
def createActions(n):
    action_list=[]
    nswap=n//2
    #第一种算子(Swap):前半段与后半段对应位置一对一交换
    for i in range(nswap):
        action_list.append([1,i,i+nswap])
    #第二中算子(DSwap):前半段与后半段对应位置二对二交换
    for i in range(0,nswap-1,2):
        action_list.append([2,i,i+nswap])
    #第三种算子(Reverse):指定长度的序列反序
    for i in range(0,n,4):
        action_list.append([3,i,i+3])
    return action_list
# 执行邻域搜索
def doAction(node_no_seq,action):
    node_no_seq=copy.deepcopy(node_no_seq)
    if action[0]==1:
        index_1=action[1]
        index_2=action[2]
        temporary=node_no_seq[index_1]
        node_no_seq[index_1]=node_no_seq[index_2]
        node_no_seq[index_2]=temporary
        return node_no_seq
    elif action[0]==2:
        index_1 = action[1]
        index_2 = action[2]
        temporary=[node_no_seq[index_1],node_no_seq[index_1+1]]
        node_no_seq[index_1]=node_no_seq[index_2]
        node_no_seq[index_1+1]=node_no_seq[index_2+1]
        node_no_seq[index_2]=temporary[0]
        node_no_seq[index_2+1]=temporary[1]
        return node_no_seq
    elif action[0]==3:
        index_1=action[1]
        index_2=action[2]
        node_no_seq[index_1:index_2+1]=list(reversed(node_no_seq[index_1:index_2+1]))
        return node_no_seq

参考

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

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

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

相关文章

手机验证码认证轻松搞定,MemFire Cloud 助力应用开发

在当今移动互联网时代&#xff0c;手机验证码认证已成为众多应用必不可少的身份验证方式。然而&#xff0c;对于开发者来说&#xff0c;手机验证码认证的后端工作往往是一项繁琐且耗时的任务。MemFire Cloud提供了一套即用型解决方案&#xff0c;开发者可以轻松解决手机验证码认…

枚举(enum)/共用体(union)/结构体(struct)---详解

前言 C语言包含内置类型和自定义类型。 其实C语言中有内置类型&#xff0c;包含&#xff1a;char,short,int,long,long long,float,double,long double ,这些是C语言本身支持的现成的类型。 但仅仅只有内置类型是远远不够的&#xff0c;在描述一个复杂对象是无法使用内置类型来…

einsum 表达式

Einsun 简介 ein 就是爱因斯坦的ein&#xff0c;sum就是求和。einsum就是爱因斯坦求和约定&#xff0c;其实作用就是把求和符号省略。 B torch.einsum("ij->i", A) einsum接收的第一个参数为einsum表达式&#xff0c;-> 符号就相当于要把->前面的张量变…

求三个字符数组最大者(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> # include <string.h>int main() {//初始化变量值&#xff1b;int i 0;char str[3][20];char string[20];//循环输入3个字符…

软件测试笔记_习题_面经

软件测试------按测试阶段划分有几个阶段? 单元测试、集成测试、系统测试、验收测试 软件测试------按是否查看源代码划分有几种测试方法? 黑盒、白盒、灰盒 软件测试------按是否运行划分有几种测试方法? 静态测试、动态测试 软件测试------按是否自动化划分有几种测试方…

Android 在attrs.xml添加属性时出现 Found item Attr/****** more than one time

Android 在attrs.xml添加属性时出现 Found item Attr/****** more than one time 问题描述解决办法方式一方式二 小结 问题描述 在Android应用开发过程中&#xff0c;经常需要自定义控件&#xff0c;并且定义控件的属性&#xff0c;方便灵活的修改控件的显示样式&#xff0c;提…

生成对抗网络的无载体信息隐藏算法简介

一、研究背景 随着互联网技术的广泛应用和移动智能设备的快速普及&#xff0c;人们有了更多的途径传播和获取信息。每天海量的数据以视频、音频、图像、文字等各类形式在互联网中产生&#xff0c;这为人们的生活带来了极大的便利&#xff0c;但同时也引起了人们对信息泄露的担…

从零入门区块链和比特币(第三期)

欢迎来到我的区块链与比特币入门指南&#xff01;如果你对区块链和比特币感兴趣&#xff0c;但不知道从何开始&#xff0c;那么你来对地方了。本博客将为你提供一个简明扼要的介绍&#xff0c;帮助你了解这个领域的基础知识&#xff0c;并引导你进一步探索这个激动人心的领域。…

【yolov8算法道路-墙面裂缝检测-汽车车身凹陷-抓痕-损伤检测】

yolo算法道路-墙面裂缝检测-汽车车身凹陷-抓痕-损伤检测 1. yolo算法裂缝检测-汽车车身凹陷-抓痕检测-汽车车身损伤检测2. yolo房屋墙面路面裂缝-发霉-油漆脱落-渗水-墙皮脱落检测3. 水泥墙面裂缝检测 YOLOv8算法是一种先进的目标检测技术&#xff0c;它基于YOLO系列算法的改进…

卓越体验的秘密武器:评测ToDesk云电脑、青椒云、天翼云的稳定性和流畅度

大家好&#xff0c;我是猫头虎。近两年随着大模型的火爆&#xff0c;我们本地环境常常难以满足运行这些大模型的硬件需求。因此&#xff0c;云电脑平台成为了一个理想的解决方案。今天&#xff0c;我将介绍并评测几款主流云电脑产品&#xff1a;ToDesk云电脑、天翼云电脑和青椒…

基于 SpringCloud 的在线交易平台乐优商城的设计与实现(四)

第 4 章 数据库设计 4.1 数据库设计原则 4.2.数据库概念结构设计 4.3 数据库表设计 4.4.本章小结 前面内容请移步 基于 SpringCloud 的在线交易平台乐优商城的设计与实现&#xff08;三&#xff09; 相关免费源码资源 乐优商城 第 4 章 数据库设计 4.1 数据库设计原…

现代永磁同步电机控制原理pdf及全套matlab仿真模型

现代永磁同步电机控制原理pdf及matlab仿真模型。全书包含SVPWM, DTC, Lun, smo, EKF, HFI等经典控制算法。将书中10章节涉及到的模型复原搭建模型。 模型获取链接&#xff1a;现代永磁同步电机控制原理pdf及全套matlab仿真模型

C语言 | Leetcode C语言题解之第56题合并区间

题目&#xff1a; 题解&#xff1a; /*** Return an array of arrays of size *returnSize.* The sizes of the arrays are returned as *returnColumnSizes array.* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().*/ stru…

mintab计数型测量系统分析

计数型测量系统是一种在特定领域内广泛应用的测量工具&#xff0c;它主要用于对事件发生的次数进行计数&#xff0c;而不是提供具体的数值数据。这种类型的测量系统在工业生产、科研领域以及通信、电子和航空航天等多个领域都有广泛的应用价值。计数型测量系统的分析方法包括重…

matlab回归学习

前言 所谓回归学习即预测&#xff0c;便是由已知的数据推测未知的数据&#xff0c;利用转速与转矩来推测电流。 1、数据准备 下面虚拟一组转速转矩以及电流数据。 speed [100 220 330 440 550 660]; torque [200 300 400 500 700 900]; I [400 500 603 739 821 912]; arr …

职场进阶秘籍:张驰咨询的六西格玛黑带培训!

你们是否对“六西格玛黑带培训”感到好奇&#xff1f;别担心&#xff0c;这不是什么遥不可及的概念&#xff0c;而是一次能让你职场生涯焕然一新的机会&#xff01; 六西格玛黑带培训在张驰咨询 在张驰咨询&#xff0c;我们提供的六西格玛黑带培训&#xff0c;就像是一把为你量…

mysql-sql-练习题-2

日期topN 日期最值 topN 任意区间topN 每年温度top2建表排名函数万能公式&#xff08;条关&#xff09; 任意区间 各科第1,3,5名排名函数万能公式 日期 本周过生日 -- 本周表示 加减日期 格式化 拼接 select * from student where date_format(s_age,concat(year(curdate()),…

微信小程序开发:2.小程序组件

常用的视图容器类组件 View 普通的视图区域类似于div常用来进行布局效果 scroll-view 可以滚动的视图&#xff0c;常用来进行滚动列表区域 swiper and swiper-item 轮播图的容器组件和轮播图的item项目组件 View组件的基本使用 案例1 <view class"container"&…

【FPGA】优化设计指南(一):设计原则

目录 避免采用不可综合的语句设计时采用同步的时钟组合逻辑与毛刺异步复位与同步复位动态分析与静态分析功能流水线时序违例乒乓操作面积和速度的平衡避免采用不可综合的语句 1.#1000延时语句 2.除法运算/,除非除数为2的整次幂 3.实数类型不可综合(real) 4.综上,使用可综合…

远程连接docker,实现本地发布版本到服务器

最近在学jenkins的时候&#xff0c;发现涉及到了docker的远程发布调用。后续应该还要自己搭建一个docker的本地仓库。 简单描述一下具体是如何实现的&#xff1a; 1、将docker的服务器开启2375端口&#xff08;注意&#xff0c;这里的开启是将端口直接暴露出去&#xff0c;不用…
最新文章