文章目录

  • 1. 问题定义
  • 2. 数学模型
  • 3. python调用SCIP实现代码
  • 4. 结果
  • 参考文献

1. 问题定义

带时间窗车辆路径问题(vehicle routing problem with time windows,VRPTW)是在CVRP (Capacitated vehicle routing problem)问题基础上引入了顾客需求点对于车辆到达时间的要求,即每个顾客点都有一个对应的[最早到达时间,最晚到达时间]时间窗限制。

因此在该问题的目标函数中,除了要考虑车辆的行驶成本还包括车辆提前到达客户点等待的时间和顾客需要的服务时间。对于时间窗的处理,常见的有两种方式 :

  1. 硬时间窗,要求车辆必须在客户要求的服务时间窗口内到达,提前到达需等待,延误到达则拒收;
  2. 软时间窗,车辆可以不在服务时间窗内到达,但无论提前还是延误都会进行一定的惩罚。

2. 数学模型

  • 建立multi-commodity network flow model,数学模型直接参考教材《Column Generation》第三章
  • 线性化及大M的取值
  • Solomon算例下载地址:https://www.sintef.no/projectweb/top/vrptw/100-customers/

3. python调用SCIP实现代码

import os
import re
import math
import pandas as pd
import numpy as np
import pyscipopt as opt
import matplotlib.pyplot as pltclass VrpTW(object):def __int__(self):self.customerNum = 0  # 顾客点数量self.vehicleNum  = 0  # 车辆数self.capacity    = 0  # 车容量self.cor_X       = []  # x轴坐标self.cor_Y       = []  # y轴坐标self.demand      = []  # 顾客点的需求self.readyTime   = []  # 顾客点左时间窗self.dueTime     = []  # 顾客点右时间窗self.serviceTime = []  # 车辆到达节点需服务的时间self.nodeNum     = 0  # 顶点数量self.disMatrix   = [[]]  # 路径成本def read_data(self):# 通用算例下载地址:https://www.sintef.no/projectweb/top/vrptw/100-customers/with open('./solomon/solomon_25/R101.txt') as file:lines = file.readlines()# 第5行 NUMBER CAPACITYself.vehicleNum, self.capacity = list(map(int, re.split(r" +", lines[4][:-1].strip())))# 第10行到最后一行分别存储. CUST NO, XCOORD, YCOORD, DEMAND, READY TIME, DUE DATE, SERVICE TIMEcust_data = np.array([list(map(int, re.split(r" +", i[:-1].strip()))) for i in lines[9:]])self.cor_X = cust_data[:, 1]self.cor_Y = cust_data[:, 2]self.demand = cust_data[:, 3]self.readyTime = cust_data[:, 4]self.dueTime = cust_data[:, 5]self.serviceTime = cust_data[:, 6]def prepare_date(self):"""根据不同的算例需要手动配置的车辆数及顾客点"""self.vehicleNum = 8  # 手动设置车辆数self.customerNum = 25  # 手动设置取出顾客点的数量"""# 处理取出顾客点及仓库点的数据,并为了方便处理将仓库点复制插入至最后# 假设有n个顾客点 C = {1,2, ...N},并将仓库点(0)和仓库点的复制作为第n+1一个虚拟点 (这样nodeNum=customerNum + 2)# 举例 顾客点集合 C = {1,2, ...N}, 顶点集合 N = C U {0, n+1}"""row_num = self.customerNum + 1  # 设置截取数据集的row_num行,其中第1行为仓库点,所以行数=customerNum+1self.cor_X = np.append(self.cor_X[:row_num], self.cor_X[0])self.cor_Y = np.append(self.cor_Y[:row_num], self.cor_Y[0])self.demand = np.append(self.demand[:row_num], self.demand[0])self.readyTime = np.append(self.readyTime[:row_num], self.readyTime[0])self.dueTime = np.append(self.dueTime[:row_num], self.dueTime[0])self.serviceTime = np.append(self.serviceTime[:row_num], self.serviceTime[0])self.nodeNum = self.customerNum + 2# 计算欧式距离矩阵self.disMatrix = np.full((self.nodeNum, self.nodeNum), 0)for i in range(self.nodeNum):for j in range(self.nodeNum):self.disMatrix[i][j] = math.sqrt((self.cor_X[i] - self.cor_X[j]) ** 2 + (self.cor_Y[i] - self.cor_Y[j]) ** 2)# 大M的取值, 拉紧约束, 提高求解效率M = np.full((self.nodeNum, self.nodeNum), 0)for i in range(self.nodeNum):for j in range(self.nodeNum):M[i][j] = self.dueTime[i] + self.disMatrix[i, j] - self.readyTime[i]self.bigM = np.max(M)print('customerNum={}, nodeNum={}, vehicleNum={}, bigM={}'.format(self.customerNum, self.nodeNum, self.vehicleNum, self.bigM))def plt_route_pic(self, vrp_route):plt.figure(figsize=(10, 8))# 绘制坐标的散点图for i in range(0, self.nodeNum-1):if i == 0:plt.scatter(self.cor_X[i], self.cor_Y[i], marker='^', c='r')plt.annotate('depot', (self.cor_X[i], self.cor_Y[i]))else:plt.scatter(self.cor_X[i], self.cor_Y[i], marker='o', c='black')plt.annotate(str(i), (self.cor_X[i], self.cor_Y[i]))# 绘制箭头for idx in vrp_route:i,j,k = idxplt.arrow(self.cor_X[i], self.cor_Y[i], self.cor_X[j] - self.cor_X[i], self.cor_Y[j] - self.cor_Y[i],length_includes_head = True, head_width =0.5, head_length=0.8, fc='red', ec='red',linewidth=0.3)plt.xlabel('x')plt.ylabel('y')plt.title('VRPTW')plt.savefig('./vrptw.png')def solve_vrptw(self):model = opt.Model()# ==========定义变量==========x = {}s = {}# x_i_j_k: 0-1变量,表示车辆k经过弧(i,j), i != jfor i in range(self.nodeNum):for j in range(self.nodeNum):if i != j:for k in range(self.vehicleNum):x[i, j, k] = model.addVar(vtype='B', name='x_' + str(i) + '_' + str(j) + '_' + str(k))# s_i_k: 连续变量,表示车辆k开始服务顾客点i的开始时间for i in range(self.nodeNum):for k in range(self.vehicleNum):s[i, k] = model.addVar(vtype='C', name='s_' + str(i) + '_' + str(k))# ==========定义约束==========# 约束1: 对于每个车辆: 驶出仓库for k in range(self.vehicleNum):model.addCons(opt.quicksum(x[0, j, k] for j in range(self.nodeNum) if j != 0) == 1, name='vehicle_depart_' + str(k))# 约束2: 对于每个车辆: 驶回仓库for k in range(self.vehicleNum):model.addCons(opt.quicksum(x[i, self.nodeNum-1, k] for i in range(self.nodeNum) if i != self.nodeNum-1) == 1, name='vehicle_return_' + str(k))# 约束3:对于每个车辆: 车辆的容量约束 (3.3)for k in range(self.vehicleNum):model.addCons(opt.quicksum(self.demand[i] * x[i, j, k] for i in range(1, self.nodeNum-1) for j in range(self.nodeNum) if i!=j) <= self.capacity,name='capacity_vehicle' + str(i))# 约束4:对于顾客点: 进的车数量=1, 出的车的数量=1, 即保证每个客户点都被服务 for i in range(1, self.nodeNum-1):model.addCons(opt.quicksum(x[i, j, k] for j in range(self.nodeNum) for k in range(self.vehicleNum) if i!=j) == 1,name='customer_depart_' + str(i))model.addCons(opt.quicksum(x[j, i, k] for j in range(self.nodeNum) for k in range(self.vehicleNum) if i!=j) == 1,name='customer_enter_' + str(i))# 约束5: 对于顾客点: 进出是同一辆车,流平衡,服务之后需离开 for k in range(self.vehicleNum):for i in range(1, self.nodeNum-1):model.addCons(opt.quicksum(x[i, j, k] for j in range(self.nodeNum) if i!=j) ==opt.quicksum(x[j, i, k] for j in range(self.nodeNum) if i!=j), name='flow_' + str(k) + '_' + str(i))"""约束6: 对于顾客点和仓库的时间窗口约束对于顾客点的时间窗口: 只有车辆k服务了顾客点i此约束,才会有时间窗口的约束;服务时间需在窗口范围内"""ready_time, due_time = {}, {}  # 临时变量for i in range(1, self.nodeNum-1):for k in range(self.vehicleNum):ready_time[i, k] = model.addVar(vtype='C', name='ready_time_' + str(i) + '_' + str(k))due_time[i, k] = model.addVar(vtype='C', name='due_time_' + str(i) + '_' + str(k))model.addCons(ready_time[i, k] == opt.quicksum(self.readyTime[i] * x[i, j, k] for j in range(self.nodeNum) if i!=j))model.addCons(due_time[i, k] == opt.quicksum(self.dueTime[i] * x[i, j, k] for j in range(self.nodeNum) if i!=j))model.addCons(ready_time[i, k] <= s[i, k], name='cons_ready_time_' + str(i) + '_' + str(k))model.addCons(due_time[i, k] >= s[i, k], name='cons_due_time_' + str(i) + '_' + str(k))# 对于仓库点的时间窗口约束: 在时间点0在仓库,最终有回来时间时间要求for k in range(self.vehicleNum):model.addCons(s[0, k] == 0)  # 所有车出发时间为0model.addCons(s[self.nodeNum-1, k] >= self.readyTime[self.nodeNum-1])model.addCons(s[self.nodeNum-1, k] <= self.dueTime[self.nodeNum-1])"""约束7: 保证被服务的相邻节点间访问时间顺序(消除除子回路)x_i_j_k * (s_i_k + t_i_j - s_j_k) <= 0  线性化为 (s_i_k + t_i_j - s_j_k) - (1 - x_i_j_k)* M <= 0"""for k in range(self.vehicleNum):for i in range(self.nodeNum):for j in range(self.nodeNum):if(i != j):model.addCons(s[i,k] + self.disMatrix[i][j] + self.serviceTime[i] - s[j,k] - self.bigM + self.bigM * x[i,j,k] <= 0,name= 'time_windows_' + str(i) + '_' + str(j) + '_' + str(k))# ==========定义目标==========model.setObjective(opt.quicksum(x[i, j, k] * self.disMatrix[i, j] for (i, j, k) in x))model.setMinimize()model.optimize()# ==========输出结果==========print('model_status = ', model.getStatus())print('model_gap =', model.getGap())print('model_obj =', model.getObjVal())# model.writeProblem('vrpTW.lp')vrptw_route = []for k in range(self.vehicleNum):for i in range(self.nodeNum):for j in range(self.nodeNum):if(i != j and model.getVal(x[i,j,k]) > 0):vrptw_route.append((i,j,k))print('vrptw_route:\n', vrptw_route)# 绘制结果路径self.plt_route_pic(vrptw_route)if __name__ == '__main__':vrp = VrpTW()# 读取数据vrp.read_data()# 预处理数据vrp.prepare_date()# 求解模型并绘制结果vrp.solve_vrptw()

4. 结果

  • C101_25

  • R101_25

参考文献

《Column Generation》Guy Desaulniers (Editor), Jacques Desrosiers (Editor), Marius M. Solomon (Editor), chapter 3

python调用开源求解器SCIP求解带时间窗车辆路径问题(VRPTW)相关推荐

  1. 【TWVRP】基于matlab蚁群算法求解带时间窗车辆路径规划问题【含Matlab源码 1930期】

    ⛄一.VRP简介 1 VRP基本原理 车辆路径规划问题(Vehicle Routing Problem,VRP)是运筹学里重要的研究问题之一.VRP关注有一个供货商与K个销售点的路径规划的情况,可以简 ...

  2. 【路径规划】基于遗传算法求解带时间窗车辆路径规划问题(VRPTW)matlab源码

    1 简介 有时间窗的车辆路径问题(Vehicle Routing Problem with Time Windows,VRPTW)因为其有重要的现实意义而备受关注.其时间窗即为客户接受服务的时间范围, ...

  3. 【TWVRP】蚁群算法求解带时间窗车辆路径规划问题【含Matlab源码 1930期】

    ⛄一.VRP简介 1 VRP基本原理 车辆路径规划问题(Vehicle Routing Problem,VRP)是运筹学里重要的研究问题之一.VRP关注有一个供货商与K个销售点的路径规划的情况,可以简 ...

  4. 求解带时间窗车辆路径问题的多目标模因算法

    https://blog.csdn.net/zhangkkit/article/details/105928806

  5. MATLAB实战系列(十二)-如何用人工鱼群算法解决带时间窗车辆路径(CVRP)问题(附MATLAB代码)

    前言: 本文大体的思路是先对人工鱼进行编码,然后采用人工鱼群算法求解TSP问题中的觅食.聚群.追尾和随机行为对人工鱼群进行更新. 但是亟需需要解决的问题是:对于CVRP问题,如何对人工鱼进行编码.如果 ...

  6. Matlab车辆配送路径规划问题 各类vrp代码 带时间窗的路径规划问题

    Matlab车辆配送路径规划问题 各类vrp代码 带时间窗的路径规划问题 遗传算法 蚁群算法 模拟退火算法 混合粒子群算法解决 tsp cvrp dvrp cdvrp vrptw问题 tsp:旅行商问 ...

  7. 时间窗车辆路径问题matlab代码,【图片】蚁群算法求解有时间窗约束的车辆路径问题matlab程序_蚁群算法吧_百度贴吧...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 蚁群算法求解有时间窗约束的车辆路径问题matlab程序 1 简介 带时间窗的车辆路径问题(VRPTW)一般描述为从某一物流配送中心出发,用多台车辆向多个顾 ...

  8. python调用开源求解器scip求解运输问题

    运输问题 运输问题(transportation problem)一般是研究把某种商品从若干产地运至若干个销地而使总运费最小的一类问题.一种特殊的线性规划问题,由于其技术系数矩阵具有特殊的结构,可以使 ...

  9. python调用求解器SCIP求解设施选址覆盖问题

    文章目录 1. 设施选址集合覆盖问题 2. 算法实现 2.1 测试数据集 OR-Library 2.2 python调用SCIP求解设施选址覆盖问题完整代码: 2.3 数据结果 参考文献 1. 设施选 ...

最新文章

  1. Springboot启动原理解析
  2. 发表论文不用愁,十大技巧治秃头
  3. [开源] .NETCore websocket 即时通讯组件---ImCore
  4. (chap4 IP协议) 多播和子网掩码
  5. c语言那些细节之a+1和a+1的区别
  6. python selenium webdriver方法封装(find_element_by)
  7. 安装laravel5.1项目命令
  8. mysql -u 报错_MySQL报错解决!
  9. Cloud for Customer UI checkbox控件在PC和mobile端的不同显示
  10. android中ActionBar的几个属性
  11. sprintf_s与_snprintf与_snprintf_s
  12. vue如何判断已经有定时器在执行_中国股市:如何判断当日涨跌?“分时图”已经全部告诉你了...
  13. [Ubuntu] 软链接
  14. c语言程序设计 cap 翁恺,GPS数据处理 翁恺老师C语言程序设计CAP第10章编程题
  15. mexcuda输入nvcc中的参数
  16. usb接口驱动_技术丨USB接口无法识别设备的处理方法
  17. java模板引擎哪个好_Java 常用模板引擎推荐
  18. 【博主推荐】html好看的个人简历网页版(附源码)
  19. 微信qq表情输入文本 vue
  20. 将bilibili里面的缓存视频保存到电脑

热门文章

  1. 汽车软件开发者的内功心法:V模型
  2. 选择功率电阻一定要注意,这个电阻选不好,就可以烤肉了
  3. AttentionTransformer
  4. C++与Lua相互调用
  5. python+selenium的一个小蜘蛛
  6. 虚拟主机配置邮件服务
  7. element tree组件 鼠标移入显示设置,dropdown下拉框可以创建编辑删除节点
  8. 每天一个 Linux 命令(56):netstat命令
  9. 朝鲜版linux:《Red Star 2.0》体验手记
  10. 机器学习算法地图(高清图)