干货 | 列生成VRPTW子问题ESPPRC( Elementary shortest path problem with resource constraints)介绍附C++代码

00 前言

各位小伙伴大家好,相信大家已经看过前面column generation求解vehicle routing problems的过程详解。该问题中,子问题主要是找到一条reduced cost最小的合法路径,然后加入到Master Problem中。其实,子问题也是一个著名的NP-Hard问题,今天我们就来介绍一下。

01 ESPPRC

考虑图1.1中描述的网络。 除了每条边的成本c_ij之外,还存在经过边(i,j)的所消耗的资源t_ij,比如时间。 我们的目标是找到从开始节点到结束节点的最短路径,每个节点只能访问一次,同时使得资源消耗满足可用的资源约束,比如全程不能超过多少时间。[1]

当然上面描述问题只是ESPPRC中的一个例子,实际的资源约束可能有很多种,比如在VRPTW的子问题中:[2]

起始节点和结束节点一样,每个节点有固定的时间窗和固定的需求。车辆不能超过容量约束的要求等等。

ESPPRC vs SPPRC

SPPRC和ESPPRC一样,只不过SPPRC去掉了elementary的约束,允许最短路中一个节点被访问多次。

02 应用

我们知道,ESPPRC是可以应用在column generation中的算法框架中的。那么具体是怎么应用的呢?我们知道,在column generation中,subproblem每次迭代就是找一条reduced cost最小的路径,然后加入到Master Problem中。但是对于ESPPRC来说,每次的cost一样的,那不每次都求出同一条路径吗???

不!在column generation中,其子问题ESPPRC中边的cost是会随着Master Problem的求得到对偶变量改变而改变的。还记得reduced cost是怎么计算的吗?

其中,式子(22)可以表达成式子(23),(23)是什么意思呢?b_ijk意思是边ij是否在路径k中。那么,在每一次迭代中,我们就可以利用Master Problem的对偶变量,来更新ESPPRC中每条边的cost,最终求得的路径cost就是column generation中的reduced cost。

03 常见的算法

ESPPRC的建模如下:[4]


求解SPPRC和ESPPRC常见的算法主要有以下几种:[3]

  • Dynamic programming and labeling algorithms
  • Lagrangean relaxation
  • Constraint programming(建模)
  • Heuristics

04 Pulse Algorithm

这一节介绍一个ESPPRC的精确算法Pulse Algorithm[5],算法的伪代码如下:

其中:

  • r:表示到达当前节点时的cost
  • q:表示到达当前节点时的装载量
  • t:表示到达当前节点所需的总时间,早到需要等待,不能晚到

大体的思想是通过bound算法确定到达每个节点的最低cost,然后pulse进行路径搜索,而之前bound求出来的最低cost就可以在pulse搜索的过程中起到定界的作用,去掉一些不好的路径。

bound的算法如下:

每个节点的最低cost(相当于一个lower bound)是怎么算出来的呢?简单来说是通过限定每个节点最晚到达时间。在每个节点都给定最晚到达时间t,然后计算在这个最晚到达时间下,每个到达每个节点的最低cost。然后让t递减,直到t减少到临界值。最终得到的是每个节点关于各个最晚到达时间的最低cost矩阵。

最后来看看pulse算法:

pulse是找路的过程,在该过程中:

  • isFeasible检查到达节点时路径是否满足各种资源约束。
  • checkBounds检查在当前到达时间下,到达节点的cost是否小于等于之前bound算法求出来的那个最晚时间下的最低cost,如果不是就丢弃该支路径。
  • rollback进行如下检查:

在每一个节点(开始节点除外),比如上图中节点j,如果实线路径的cost < 虚线路径的cost。那么砍掉实线的路径(已经有人的cost比你更低,你可以滚了),这就相当于一个回滚的操作。

以上>>>>>>>>>>>>>>>>>>>>>就是整个pulse算法。这里只是起到一个抛砖引玉的过程。可能讲的不是很详细,详细的过程请大家去阅读文献。

05 算法代码

关于整个pulse算法伪代码和讲解已经够详细了,这里给出一个C++的实现代码,是我远房的一个学长的学姐的男朋友写的(真话)。关于编译运行上面也说明得够详细了。

代码下载请关注我们的公众号哦!在后台回复【espprc】不包括【】即可下载。

reference

  • [1] A PRIMER IN COLUMN GENERATION, Jacques Desrosiers Marco E. L ubbecke
  • [2] A tutorial on column generation and branch-and-price for vehicle routing problems, Dominique Feillet
  • [3] SHORTEST PATH PROBLEMS WITH RESOURCE CONSTRAINTS, Stefan Irnich Guy Desaulniers
  • [4] An Exact Algorithm for the Elementary Shortest Path Problem with Resource Constraints: Application to Some Vehicle Routing Problems, Dominique Feillet, Pierre Dejax, Michel Gendreau, Cyrille Gueguen
  • [5] An Exact Algorithm for the Elementary Shortest Path Problem with Resource Constraints, Leonardo Lozano, Daniel Duque, Andrés L. Medaglia

原文地址:https://www.cnblogs.com/dengfaheng/p/11379400.html

时间: 2024-10-31 07:52:37

干货 | 列生成VRPTW子问题ESPPRC( Elementary shortest path problem with resource constraints)介绍附C++代码的相关文章

python 用户在键盘上输入一个自然数n,然后在区间[1, 5n]上随机生成n个不重复的自然数,输出这些自然数, 然后继续编写代码对这些自然数进行处理,只保留所有偶数,并输出这些偶数

#用户在键盘上输入一个自然数n,然后在区间[1, 5n]上随机生成n个不重复的自然数,输出这些自然数,# 然后继续编写代码对这些自然数进行处理,只保留所有偶数,并输出这些偶数import randomn=int(input("请输入整数"))shu=set()i=0while True: num=random.choice(range(1,5*n+1))#生成随机数 shu.add(num) if len(shu)==n: breakprint("n个不重复的随机数是:&qu

请教列生成算法

l3syfb仙爸晾僦狈刎<http://weibo.com/p/230927983029891500871680?=2> hdwtxx牧驶倚隙赣防<http://weibo.com/20180410p/230927983058738862624768?=n> 4673po崖腺繁炼邢哨<http://weibo.com/p/230927983218117477928960?=Q> vodwxd橙狼河裂沟垂<http://weibo.com/p/23092798315

pandas 选择列或者添加列生成新的DataFrame

选择某些列 import pandas as pd # 从Excel中读取数据,生成DataFrame数据 # 导入Excel路径和sheet name df = pd.read_excel(excelName, sheet_name=sheetName) # 读取某些列,生成新的DataFrame newDf = pd.DataFrame(df, columns=[column1, column2, column3]) 选择某些列和行 # 读取某些列,并根据某个列的值筛选行 newDf = p

动态竖列生成button

using UnityEngine;using System.Collections;using UnityEngine.UI; /// <summary>/// 用来测试动态生成下载列表/// </summary>public class UILoad : MonoBehaviour{ int contDown = 4; //初始位置 int lbx = 200; //下载列表 public GameObject DownControl0; // Use this for ini

python提取Excel中的特定列生成新的表格

#coding=utf-8 import xlrd,chardet,traceback,csv #根据列名获取相应序号 def getColumnIndex(table,columnName): columnIndex=None for i in range(table.ncols): if(table.cell_value(0,i)==columnName): columnIndex=i break return columnIndex #根据Excel中sheet名称读取数据 def rea

Thinkphp3.2结合phpqrcode生成二维码(含Logo的二维码),附案例

首先,下载phpqrcode,将其解压到项目ThinkPHP\Library\Vendor目录下.Index_index.html(模板可自行配置) <form action="{:U('index/index')}" enctype="multipart/form-data" method = "post"> <b>尺寸大小:</b> <input type="text" name

JS子父窗口互相操作取值赋值的方法介绍

$("#父窗口元素ID",window.parent.document); 对应javascript版本为window.parent.document.getElementByIdx_x("父窗口元素ID"): 取父窗口的元素方法:$(selector, window.parent.document);那么你取父窗口的父窗口的元素就可以用:$(selector, window.parent.parent.document); 类似的,取其它窗口的方法大同小异$(se

sql查询列进行STUFF()拼接 单引号 逗号_xml path excel

有时候查询出的某一列结果要作为其他数据库查询条件,必须要做拼接转换 方法: SELECT [id] = stuff((SELECT distinct ',''' + t.id + '''' FROM table t WHERE t.id = 1 FOR xml path ('')),1,1,'');方法使用如下: SELECT [Id] = STUFF((SELECT DISTINCT ',''' + Ld + '''' FROM BaseMeterFieldType AS b WHERE b.

投掷100次掷子计算每个数出现的次数 C#源码案例 附第二种简单解法

Console.WriteLine("投掷100次的实验:"); //提示信息 Random randomNum = new Random(); //创建一个随机数 int num1 = 0; //定义出现1的次数 int num2 = 0; //定义出现2的次数 int num3 = 0; //定义出现3的次数 int num4 = 0; //定义出现4的次数 int num5 = 0; //定义出现5的次数 int num6 = 0; //定义出现6的次数 for (int i =