如何写代码实现VRP问题中车辆容量限制及时间窗要求(python)

问题研究背景

使用遗传模拟退火算法求解如下10个卸货点的VRPTW问题。为了使研究的问题更加有意义,本人将时间限理解为服务点一天的具体可以允许配送的时间。 如果不要求车辆从配送中心出发的时间是统一的并且为0时刻,那么就默认第一个配送节点是一定能赶到的。采取从配送中心出发的时间不为0时刻的策略,默认一定能达到第一个配送点,所以采用最早到达时间推算车辆出发的时间。
假设配送中心营业时间是早上七点至晚上七点,即配送中心也有最早和最晚时间窗要求,车辆配送货物应该满足这个发车即回到配送中心的最晚时间限制。卸货点1-10的时间限制理解如下:卸货点1要求在下午1点至下午4点配送,卸货点1要求的服务时间是半个小时;卸货点2要求在下午4点至下午6点配送,卸货点2要求的服务时间是1个小时,以此类推其他的卸货点的配送及服务时间限制。算法中用到配送及服务时间是下午的情况,例如卸货点1可转成数字表示是[13,16]。

在这里插入图片描述

配送点的需求货物量如下:

在这里插入图片描述

配送点的达到时间窗及服务时间如下:

在这里插入图片描述

代码编码思路

取染色体,依次判断染色体的基因是否满足车辆载重量及时间窗限制条件,染色体基因片段如果不满足两者,则默认为一条路线,在中间插入配送中心节点0.

考虑是否可以写两个独立的函数,先判断车辆的载重量限制,再前面生成的解再次寻优判断是否满足时间窗限制。

编写代码过程中遇到的错误

从配送中心出发立即回到配送中心

chrom [10  1  5  2  3  6  4  9  7  8]
*******000******
*******000******
routes [[0, 0, 0]]

当首次配送的需求点为卸货点10时,最早到达时间要求是下午5点,配送中心开门是上午七点,关门是下午七点,两点之间的路径长度是160公里,车辆每小时的车速是40公里/小时,所以最佳的方案是不考虑先去卸货点10完成配送任务,因为车辆返回时赶不上配送中心的关门时间。

在这里插入图片描述

一些其他的错误

opulation [[ 7  6  1  2  9  3  4  5  8 10][ 3  2  5 10  7  4  6  8  1  9][ 4  6  8  7  1  9  5  3  2 10][10  5  7  2  6  4  3  9  8  1][ 9  7 10  8  2  1  4  5  3  6][ 5 10  9  3  6  1  2  4  8  7][ 5  6  2  7  3 10  9  4  8  1][ 2  9  1  3 10  8  6  4  5  7][ 7  3  1  6  2 10  9  8  4  5][10  4  5  9  6  7  3  2  1  8][ 2  4  3  5  8  6  7  1 10  9][ 9  2  6  8  3  1  5  4 10  7][10  2  9  5  1  4  6  3  8  7][ 4  9  5  2  6  1 10  3  8  7][ 7  4  6  8  9 10  3  2  1  5][10  1  4  9  6  2  3  5  7  8][10  9  5  4  3  2  8  1  7  6][ 7  3  8  1 10  5  4  2  9  6][ 3  9 10  4  6  7  5  2  1  8][ 5 10  3  6  4  7  9  1  2  8][ 5  7  3  6  1  2  4  9 10  8][ 3  9  1 10  5  4  2  7  6  8][10  7  1  2  5  8  6  9  4  3][10  6  8  2  9  7  4  5  1  3][ 4  2  7  1  9  3 10  5  8  6][ 7  4  5  8  1  3  9  6 10  2][ 4  1  7  5  9  2  3 10  8  6][ 5  3  1 10  8  9  7  6  4  2][ 7  3  4  5  9  6  8  1 10  2][ 4  2  5 10  1  9  6  7  8  3][ 1  6  4  2 10  7  3  8  9  5][ 9  4  3  6  8 10  2  1  7  5][ 4  7  2  3  9 10  1  5  6  8][ 5  6 10  8  9  7  2  1  3  4][ 8  3  9  1  6  5  4 10  7  2][ 5  7  4  9  3  8 10  1  2  6][ 7  2  9  1  6  5  4 10  3  8][ 6 10  4  5  8  7  1  3  9  2][ 9  5 10  8  3  6  7  2  1  4][ 5  6  3 10  4  9  8  7  1  2][ 7  1  8  6  2  3  9  5 10  4][ 9  1  8  7  4  3  2  6 10  5][ 7  3  2 10  1  6  4  9  8  5][ 5  9  6  3  7  2  8  4  1 10][ 1  2  4  7  8  5  3  6  9 10][ 3  7  2  1  6 10  5  9  4  8][ 7  5  9  3  8  4 10  2  1  6][ 5  6  8 10  9  3  7  4  1  2][ 3  9  7  6  5  2 10  1  4  8][ 3  4  2  7  1  9  8  5 10  6]]
chrom [ 7  6  1  2  9  3  4  5  8 10]
*******000******
total_path_list [[0, 7, 6, 0], [0, 1, 2, 9, 0], [0, 3, 0], [0, 4, 5, 8, 0], [0, 10, 0]]
node 2
node 3
new_chrom [2, 3, 0, 9, 0, 0]
*******000******
total_path_list [[0, 0, 9, 0]]
new_chrom [9]
*******000******
total_path_list [[0, 9, 0]]
node 9
new_chrom [9]
routes [9]
cannotbe_firstnode_served [4, 5, 7, 10]
*******000******
total_path_list [[0, 5, 1, 2, 0], [0, 10, 0], [0, 4, 6, 0], [0, 3, 0], [0, 7, 8, 0], [0, 9, 0]]
path_list [0, 5, 1, 2, 0]
path_list [0, 10, 0]
path_list [0, 4, 6, 0]
path_list [0, 3, 0]
path_list [0, 7, 8, 0]
path_list [0, 9, 0]
new_chrom [3, 9, 5, 10, 4, 7]
*******000******
total_path_list [[0, 10, 0], [0, 4, 0], [0, 5, 0], [0, 7, 0]]
total_path_list [[0, 2, 3, 0], [0, 4, 5, 0], [0, 6, 7, 0], [0, 8, 9, 0], [0, 10, 0], [0, 1, 0]]
path_list [0, 2, 3, 0]
path_list [0, 4, 5, 0]
path_list [0, 6, 7, 0]
path_list [0, 8, 9, 0]
path_list [0, 10, 0]
path_list [0, 1, 0]
feasible_node_list [2, 3, 6, 8, 9, 1]
not_feasible_node_list [4, 5, 7, 10]
new_chrom [2, 3, 6, 8, 9, 1, 4, 5, 7, 10]Process finished with exit code 0

函数代码

修改卸货点的时间窗,增加求得时间窗+车辆载重量约束限制的可行解概率。
在这里插入图片描述

车辆容量限制的代码见本博主的博文《【纠错】遗传算法求解VRP计算车辆容量限制的代码有bug》,时间窗要求的函数如下:

def time_window_restraint(total_path_list):# 先求解车辆容量限制,再计算时间窗限制,硬时间窗限制# 如果不要求车辆从配送中心出发的时间是统一的并且为0时刻,那么就默认第一个配送节点是一定能赶到的# 采取从配送中心出发的时间不为0时刻的策略,默认一定能达到第一个配送点,所以采用最早到达时间推算车辆出发的时间# 假设配送中心营业时间是早上七点至晚上七点# 先排除算例无解的场景,即配送中心开门时间都不能实现派车辆运输的场景print("total_path_list", total_path_list)not_feasible_node_list = []feasible_node_list = []feasible_path_list = []for i in range(len(total_path_list)):path_list = total_path_list[i]arrive_time = demand_time_window[0, path_list[1]]leave_time = arrive_time + demand_service_time[path_list[1]]if path_list[1] in cannotbe_firstnode_served:not_feasible_node_list.extend(path_list[1:-1])else:# 默认第一个服务点的时间窗一定是满足要求的if len(path_list) == 3:# 返回配送中心的时间back_center_time = leave_time + travel_time_graph[path_list[-2]][0]if back_center_time > dis_center_open_time[1]:not_feasible_node_list.append(path_list[-2])else:# 只有一个配送节点的场景feasible_node_list.append(path_list[-2])else:feasible_node_list.append(path_list[1])if len(path_list) == 4:before_node = path_list[1]cur_node = path_list[2]arrive_time = leave_time + travel_time_graph[before_node][cur_node]if (arrive_time < demand_time_window[0, cur_node]) or (arrive_time > demand_time_window[1, cur_node]):# 不可行解# 判断是否加入不可行解集合if before_node in feasible_node_list:feasible_node_list.remove(before_node)not_feasible_node_list.append(before_node)not_feasible_node_list.append(cur_node)else:not_feasible_node_list.append(cur_node)else:leave_time = arrive_time + demand_service_time[cur_node]# 返回配送中心的时间back_center_time = leave_time + travel_time_graph[cur_node][0]if back_center_time > dis_center_open_time[1]:# 判断是否加入不可行解集合if before_node in feasible_node_list:feasible_node_list.remove(before_node)not_feasible_node_list.append(before_node)not_feasible_node_list.append(cur_node)else:not_feasible_node_list.append(cur_node)else:# 判断是否加入可行解集合if before_node in not_feasible_node_list:not_feasible_node_list.append(cur_node)else:feasible_node_list.append(cur_node)else:remain_node_list = path_list[2:-1]for index in range(len(remain_node_list)):cur_node = remain_node_list[index]if len(remain_node_list) == 1:before_node = remain_node_list[0]else:before_node = remain_node_list[index-1]arrive_time = leave_time + travel_time_graph[before_node][cur_node]if (arrive_time < demand_time_window[0, cur_node]) or (arrive_time > demand_time_window[1, cur_node]):# 不可行解# 判断是否加入不可行解集合if before_node in feasible_node_list:feasible_node_list.remove(before_node)not_feasible_node_list.append(before_node)not_feasible_node_list.append(cur_node)else:not_feasible_node_list.append(cur_node)else:leave_time = arrive_time + demand_service_time[cur_node]if cur_node == path_list[-2]:# 返回配送中心的时间back_center_time = leave_time + travel_time_graph[path_list[-2]][0]if back_center_time > dis_center_open_time[1]:# 判断是否加入不可行解集合if before_node in feasible_node_list:feasible_node_list.remove(before_node)not_feasible_node_list.append(before_node)not_feasible_node_list.append(cur_node)else:# 判断是否加入可行解集合not_feasible_node_list.append(cur_node)else:# 判断是否加入可行解集合if before_node in not_feasible_node_list:not_feasible_node_list.append(cur_node)else:feasible_node_list.append(cur_node)else:# 判断是否加入可行解集合if before_node in not_feasible_node_list:not_feasible_node_list.append(cur_node)else:feasible_node_list.append(cur_node)new_chrom = []if len(feasible_node_list) > 0:for node in feasible_node_list:new_chrom.append(node)if len(not_feasible_node_list) > 0:for node in not_feasible_node_list:new_chrom.append(node)not_feasible_node_flag = Trueelse:not_feasible_node_flag = Falseprint("new_chrom", new_chrom)return not_feasible_node_flag, feasible_node_list, new_chrom
def get_feasible_route(chrom):# 先判断是否满足车辆最大载重量限制cur_chrom = copy.deepcopy(chrom)not_feasible_node_flag = Truecount = 0while not_feasible_node_flag:# 先用得到满足车辆载重量的函数切出可行解路径print("*******000******")total_path_list = vehicle_capacity_restraint(cur_chrom)# 再使用时间窗判断是否路径也是满足时间窗要求的not_feasible_node_flag, feasible_node_list, new_chrom = time_window_restraint(total_path_list)print("not_feasible_node_flag", not_feasible_node_flag)if not_feasible_node_flag:print("*******001******")cur_chrom = new_chromcount += 1else:print("*******003******")return vehicle_capacity_restraint(new_chrom)if (count > 1) and (cur_chrom == new_chrom):return vehicle_capacity_restraint(new_chrom)  # 使用函数切出路线

算法迭代示意图

遗传算法迭代图如下:

在这里插入图片描述

连续两次运行程序,得到的目标值相同,下面图2比上图1在100代左右就寻找到了结果:

在这里插入图片描述

事不过三,连续三次,目标值开出来的都是478

在这里插入图片描述

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

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

相关文章

用echarts在vue2中实现3d饼图

先看效果&#xff0c;再看文章&#xff1a; 一、安装插件 3d的图不仅用到echarts&#xff0c;还用到了echarts-gl&#xff0c;因此都需要安装一下哦~ npm install echarts npm install echarts-gl2.0.9 //可以指定版本&#xff0c;也可不指定二、在main.js中引入 import * …

达索智能制造解决方案,敏捷电芯制造如何赋能企业竞争力 | 百世慧®

敏捷电芯制造赋能企业竞争力 全球电池市场正在快速扩大&#xff0c;为制造商带来巨大商机。 锂电行业的智能制造如何应用&#xff1f; 电池制造业的市场趋势是什么&#xff1f; 电池制造商面临哪些挑战&#xff1f; 特别是电池电芯制造方面&#xff0c;如何克服挑战获得竞…

竞赛 深度学习乳腺癌分类

文章目录 1 前言2 前言3 数据集3.1 良性样本3.2 病变样本 4 开发环境5 代码实现5.1 实现流程5.2 部分代码实现5.2.1 导入库5.2.2 图像加载5.2.3 标记5.2.4 分组5.2.5 构建模型训练 6 分析指标6.1 精度&#xff0c;召回率和F1度量6.2 混淆矩阵 7 结果和结论8 最后 1 前言 &…

微信小程序 —— 会议OA项目首页布局与Mock数据交互

14天阅读挑战赛如果世界上有奇迹&#xff0c;那一定是努力的另一个名字。 目录 一、小程序布局 1.1 Flex布局 1.2 Flex属性 二、OA会议首页搭建 2.1 首页底部菜单 2.2 创建后端结口 2.3 Mock模拟数据 2.4 首页轮播图搭建 2.5 首页内容搭建 一、小程序布局 1.1 Flex布…

产品新闻稿撰写流程是怎样的,纯干货

企业和品牌每年都会投放大量的产品新闻稿&#xff0c;一篇优质的产品新闻稿可以掀起更多的关注&#xff0c;收获更多的流量&#xff0c;如何在众多的新闻稿中脱颖而出&#xff0c;吸引读者的注意力&#xff1f;本文伯乐网络传媒将为您揭秘产品新闻稿撰写流程&#xff0c;教您如…

基于epoll封装非阻塞的reactor框架(附源码)

C++常用功能源码系列 文章目录 C++常用功能源码系列前言一、reactor架构二、client端reactor代码三、server端reactor代码四、单reactor架构可以实现百万并发总结前言 本文是C/C++常用功能代码封装专栏的导航贴。部分来源于实战项目中的部分功能提炼,希望能够达到你在自己的项…

学会C++之后,为什么学任何语言都会更加容易?

学会C之后&#xff0c;为什么学任何语言都会更加容易&#xff1f; 编程的本质是把自然语言翻译为机器语言&#xff0c;但机器没有联想力&#xff0c;所以它需要编写者事无巨细地告诉它怎么做。最近很多小伙伴找我&#xff0c;说想要一些c语言资料&#xff0c;然后我根据自己从业…

什么是美颜sdk?直播实时美颜sdk的工作流程和架构分析

在现代社交媒体和娱乐行业中&#xff0c;直播已经成为了一种受欢迎的娱乐形式&#xff0c;同时实时美颜也变得越来越重要。直播实时美颜SDK的工作流程和架构在这一领域起到了关键作用。本文将深入探讨这些SDK的内部机制&#xff0c;从而理解它们如何为用户提供出色的美颜效果。…

Pytest测试框架搭建的关键6个知识点(建议收藏)

在现代软件开发中&#xff0c;测试是确保代码质量和功能稳定性的关键步骤。而Pytest作为一个功能强大且易于使用的Python测试框架&#xff0c;为我们提供了一个优雅的方式来编写和管理测试。本文将为你介绍如何构建高效可靠的测试环境&#xff0c;着重探讨Pytest测试框架搭建时…

LinkedList 源码解析(JDK1.8)

目录 一. 前言 二. 常用方法 三. 源码解析 3.1. 属性和内部类 3.2. 构造函数 3.3. 添加元素 3.4. 获取元素 3.5. 删除元素 3.6. 迭代器 3.6.1. 头到尾方向的迭代 3.6.2. 尾到头方向的迭代 3.6.3. add() 插入元素 3.6.4. remove() 移除元素 一. 前言 LinkedList同时…

TS使用echarts柱状图鼠标放上去并弹出

效果 代码 <template><div><Chart style"width: 100%; height: 344px" :option"chartOption" /></div> </template><script lang"ts" setup>import { ref } from vue;import { ToolTipFormatterParams } f…

Keeplived安装部署(单机双机)

Keeplived官网&#xff1a;https://www.keepalived.org/download.html 一 单机安装配置: 1.上传keepalived安装包并且安装 [rootmaster1 local]# tar -zxvf keepalived-2.2.8.tar.gz [rootmaster1 local]# mv keepalived-2.2.8 keepalived [rootmaster1 local]# chown root:r…

智能井盖是什么?万宾科技智能井盖传感器有什么特点

智能井盖是一种基于物联网和人工智能技术的新型城市设施。它不仅具备传统井盖的功能&#xff0c;还能通过数字化、自动化的方式实现远程监控和智能管理&#xff0c;提升城市运行效率和服务水平。 WITBEE万宾智能井盖传感器EN100-C2是一款井盖异动监测的传感终端。对窨井盖状态(…

分享一下微信公众号抽奖活动怎么弄

微信公众号抽奖活动是一种非常有效的营销手段&#xff0c;可以吸引大量用户参与&#xff0c;提高品牌曝光度和用户粘性。下面将介绍如何策划和实施一个成功的微信公众号抽奖活动。 一、明确活动目的 首先&#xff0c;需要明确微信公众号抽奖活动的目的。通常&#xff0c;抽奖活…

同花顺动态Cookie反爬JS逆向分析

文章目录 1. 写在前面2. 请求分析3. Hook Cookie4. 补环境 1. 写在前面 最近有位朋友在大A失意&#xff0c;突发奇想自己闲来无事想要做一个小工具&#xff0c;监测一下市场行情的数据。自己再分析分析&#xff0c;虽是一名程序员但苦于对爬虫领域相关的技术不是特别熟悉。最后…

万宾科技智能井盖传感器特点介绍

当谈论城市基础设施的管理和安全时&#xff0c;井盖通常不是第一项引人注目的话题。然而&#xff0c;传统井盖和智能井盖传感器之间的差异已经引起了城市规划者和工程师的广泛关注。这两种技术在功能、管理、安全和成本等多个方面存在着显著的差异。 WITBEE万宾智能井盖传感器E…

bug记录——设置了feign的fallback,但是没有生效

问题描述 feign的代码 package com.tianju.order.feign;import com.tianju.order.feign.fallback.StorageFallback; import com.tinaju.common.dto.GoodsDto; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMap…

Edge---微软浏览器-兼容性问题-解决办法(详细)

图片现象&#xff1a; 快捷键&#xff1a;winR &#xff08;进入管理员命令窗口&#xff09; 输入&#xff1a;regedit &#xff08;进入注册表编辑器&#xff09; 点击文件夹&#xff1a;HKEY_LOCAL_MACHINE 找到这个路径的文件项&#xff1a;HKEY_LOCAL_MACHINE\SOFTWARE…

web前端面试-- IEEE754标准JS精度丢失问题0.1+0.2!=0.3、0.2+0.3==0.5 十进制转二进制讲解

本人是一个web前端开发工程师&#xff0c;主要是vue框架&#xff0c;整理了一些面试题&#xff0c;今后也会一直更新&#xff0c;有好题目的同学欢迎评论区分享 ;-&#xff09; web面试题专栏&#xff1a;点击此处 背景 WEB前端面试官&#xff1a;0.20.3是否等于0.5&#xff…

JDBC-day06(数据库连接池)

八&#xff1a;数据库连接池 1. 传统连接数据库的模式 在使用开发基于数据库的web程序时&#xff0c;传统的模式基本是按以下步骤&#xff1a; 在主程序&#xff08;如servlet、bea&#xff0c;ns&#xff09;中建立数据库连接进行sql操作断开数据库连接 传统的模式存在的问…