当前位置: 首页 > 知识库问答 >
问题:

如何解释从Google OR Tools返回的车辆路径问题解决方案?

边桐
2023-03-14

我有一个使用Google的工具或python库实现的工作车辆路径问题解决方案。我有一个包含9个位置的时间矩阵,每个位置都有时间窗口。所有值均以秒为单位。

(例如,第一个时间窗口是从28800到28800。28800秒相当于上午8:00。我希望在上午8:00访问此位置,即车辆段)

我有意只用一辆车来解决这个问题(本质上是解决一个旅行推销员问题)。我相信我正确地增加了我的维度,但我肯定可能犯了一个错误——我的意图是让车辆在任何位置等待它想要的时间,就像它允许它解决车辆路径问题一样。我将上限最大值设置为86400,因为一天有86400秒,我认为考虑到这些数据,这将是一个足够高的数字。

来源

from ortools.constraint_solver import pywrapcp
from ortools.constraint_solver import routing_enums_pb2

Matrix = [
  [0,557,763,1156,813,618,822,700,112],       # Depot
  [523,0,598,1107,934,607,658,535,589],       # 1 - Location
  [631,480,0,968,960,570,451,135,582],        # 2 - Location
  [1343,1247,1367,0,1270,1289,809,1193,1253], # 3 - Location
  [746,1000,1135,1283,0,1003,1186,1071,776],  # 4 - Location
  [685,627,810,1227,990,0,712,709,550],       # 5 - Location
  [869,718,558,732,1105,650,0,384,821],       # 6 - Location
  [679,528,202,878,1008,618,412,0,630],       # 7 - Location
  [149,626,762,1124,696,532,821,698,0]        # 8 - Location
]

Windows = [
  [ 28800, 28800 ], # Depot
  [ 43200, 43200 ], # 1 - Location
  [ 50400, 50400 ], # 2 - Location
  [ 21600, 79200 ], # 3 - Location
  [ 21600, 79200 ], # 4 - Location
  [ 21600, 79200 ], # 5 - Location
  [ 21600, 79200 ], # 6 - Location
  [ 21600, 79200 ], # 7 - Location
  [ 21600, 79200 ]  # 8 - Location
]

# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(Matrix), 1, 0)

# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)

# Create and register a transit callback.
def time_callback(from_index, to_index):
  # Returns the travel time between the two nodes.
  # Convert from routing variable Index to time matrix NodeIndex.
  from_node = manager.IndexToNode(from_index)
  to_node = manager.IndexToNode(to_index)
  return Matrix[from_node][to_node]

transit_callback_index = routing.RegisterTransitCallback(time_callback)

# Define cost of each arc.
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

# Add Time Windows constraint.
routing.AddDimension(
    transit_callback_index,
    86400,  # An upper bound for slack (the wait times at the locations).
    86400,  # An upper bound for the total time over each vehicle's route.
    False,  # Determine whether the cumulative variable is set to zero at the start of the vehicle's route.
    'Time')
time_dimension = routing.GetDimensionOrDie('Time')

# Add time window constraints for each location except depot.
for location_idx, time_window in enumerate(Windows):
  if location_idx == 0:
    continue
  index = manager.NodeToIndex(location_idx)
  time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])

# Add time window constraints for each vehicle start node.
index = routing.Start(0)
time_dimension.CumulVar(index).SetRange(Windows[0][0],Windows[0][1])

# Instantiate route start and end times to produce feasible times.
routing.AddVariableMinimizedByFinalizer(time_dimension.CumulVar(routing.Start(0)))
routing.AddVariableMinimizedByFinalizer(time_dimension.CumulVar(routing.End(0)))

# Setting first solution heuristic. 
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)

# Setting local search metaheuristics:
search_parameters.local_search_metaheuristic = (routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
search_parameters.time_limit.seconds = 5
search_parameters.log_search = False

# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)

# Return the solution.
time = 0
index = routing.Start(0)
print("Locations:")
while not routing.IsEnd(index):
  time = time_dimension.CumulVar(index)
  print("{0} ({1}, {2})".format(manager.IndexToNode(index),solution.Min(time),solution.Max(time)))
  index = solution.Value(routing.NextVar(index))
print("{0} ({1}, {2})".format(manager.IndexToNode(index),solution.Min(time),solution.Max(time)))

输出

Locations:
0 (28800, 28800)
8 (28912, 42041)
5 (29444, 42573)
1 (43200, 43200)
2 (50400, 50400)
7 (50535, 50535)
6 (50947, 50947)
3 (51679, 51679)
4 (52949, 52949)
0 (52949, 52949)

我的问题是关于解决方案为我计算的输出。我对解决方案中第二个和第三个位置的时间窗口感到困惑。我希望所有的时间窗口都与结果的其余部分一样。解决方案是什么。Min()和解决方案。Max()在处理解决方案时,值是否在该问题的范围内?我在使用或工具时是否有任何明显的错误?

共有2个答案

姬英武
2023-03-14

我对这个元组的理解是

(Min_time, Max_time)

其中,Min\u time是满足时间窗口要求的最短到达时间。因为最大时间是完全相同的逻辑。

当您可以到达满足约束的节点时,程序会输出一个范围。

南门意蕴
2023-03-14
Locations:
0 (28800, 28800) // must arrive and leave no later than 28800
8 (28912, 42041) // must arrive at or after 28912 and leave no later than 42041
5 (29444, 42573) // must arrive at or after 29444and leave no later than 42573
1 (43200, 43200) // must arrive and leave no later than 43200
2 (50400, 50400) // must arrive and leave no later than 50400

请参阅我添加的评论。当到达时间是一个范围时,例如节点8或5,基本上意味着到达时间需要落在该时间范围内。只要满足条件,解决方案就仍然可行。

您可以验证如下:

Depot [28800, 28800] -> Travel (0, 8) 112-> Loc 8 [21600, 79200] -> Travel (8, 5) 532 -> Loc 5 [21600, 79200] -> Travel (5, 1) 685 -> Loc 1 [43200, 43200]

在时间28800出发,行程时间为112,您将在时间28912(您的解决方案中的最小值)到达loc 8;立即出发,行程时间为532,您将在时间29444到达loc 5。

现在,loc 1有一个可用的时间段,即43200。因此,如果车辆在时间29444离开,行驶时间为627,它将在时间30071到达位置1,这不是有效的到达时间。但是,如果车辆在43200-627=42573发车,它将准时到达。因此,这意味着车辆需要怠速(松弛)一段时间才能行驶。由于loc 8和loc 5都有一个范围,解决方案是说明这些位置有一些可用的松弛。因此,最小值和最大值真正告诉您的是,只要到达和离开在这些范围内,解决方案是可行的。

 类似资料:
  • 我们有一个具有时间和容量约束的VRP示例。 我们的场景如下: 我们有5辆车 我们的问题是,算法有时在得到新请求时,会丢弃一些我们已经标记为可行并添加到车辆调度中的节点(乘客请求)。如何防止丢弃已经添加到解决方案(然后在初始解决方案中)的节点? 我们尝试从初始解决方案中为节点设置int.max惩罚,并对我们当前添加的节点设置稍微小的惩罚。当已经确认的节点稍后被删除时,它确实减少了事件的数量,但它仍然

  • 要求 我有一个车队。每辆车都有一个容量和它的存款,这个存款有一个时间窗口。从VRP的OptaPlanner的例子来看,我只对我作为浮点处理的容量做了一个变化。据我所知,OptaPlanner示例中的所有车辆都被移动到一个仓库。在我的情况下,每辆车都有自己的车辆段,每辆车都有自己固定的车辆段,有可能几辆车都有同一个车辆段。 R2-我有访问(送货服务)。每次访问都有一个需求和一个时间窗口。从VRP的O

  • 本文向大家介绍nodejs的路径问题的解决,包括了nodejs的路径问题的解决的使用技巧和注意事项,需要的朋友参考一下 最近公司的一个开发项目,后端用的是nodejs。这两天需要打包给客户演示,就让公司一个小伙把之前3D机房的打包工具移植过来。打包之后,发现原本在开发环境下的跑的好好的项目,不能访问了。出现项目的首页不能访问的问题: can not get file index.html expr

  • 本文向大家介绍Mybatis返回插入的主键问题解决方案,包括了Mybatis返回插入的主键问题解决方案的使用技巧和注意事项,需要的朋友参考一下 MyBatis添加记录后获取主键ID,这是一个很常见的需求。这个需求有分为两种情况:(1)添加单条记录时获取主键值;(2)获取批量添加记录时各记录的主键值。 备注:MyBatis从3.3.1版本开始支持批量添加记录并返回各记录主键字段值。 1、添加单一记录

  • 本文向大家介绍python 解决函数返回return的问题,包括了python 解决函数返回return的问题的使用技巧和注意事项,需要的朋友参考一下 定义一个带返回值的函数,需要使用return语句在调用这个函数时返回一个目标值,当没有return时,函数默认返回None。 分析下面两个程序: out: 2017-9-25 out: 2017-9-25 None 对于第一个程序,仅仅调用了'no

  • 本文向大家介绍IIS7.5 无法验证对路径问题的解决方法,包括了IIS7.5 无法验证对路径问题的解决方法的使用技巧和注意事项,需要的朋友参考一下 我们用win7系统的IIS7.5发布网站时,很多人都不成功。可能会出现“无法验证对路径”的错误,本文提供解决办法 方法/步骤 1、我们添加好了物理路径和站点以后,点击右侧的基本设置 2、再点击测试设置 3、会发现测试不成功,提示:无法验证对路径,经过分