运筹系列29:routing模型之VRPPD问题
发布日期:2021-05-08 09:44:37 浏览次数:19 分类:精选文章

本文共 5345 字,大约阅读时间需要 17 分钟。

Dial-A-Ride问题与Pickup and Delivery Problem

Dial-A-Ride问题是一种经典的运输问题,涉及将多个货物按顺序运输至指定地点。在这个问题中,每个货物都有特定的起点和终点,所有运输活动从一个中心仓库(depot)开始,依次完成货物的运输任务。

Pickup and Delivery Problem的扩展

在普通的Pickup and Delivery Problem中,我们可以在Dial-A-Ride的基础上进行扩展。具体来说,只需将货物的终点设置为仓库(depot),而货物的起点则设置为仓库即可。这种方式能够简化问题,同时保持核心功能不变。

问题描述与解决方案

为了实现这一目标,我们需要一个高效的运输安排方法。以下是实现这一目标的关键步骤:

  • 数据准备:首先,我们需要定义问题的具体数据。包括:

    • 距离矩阵:表示不同地点之间的距离。
    • 运输请求:包含每个货物的起点和终点。
    • 运输工具:在本例中,我们使用4辆车进行运输。
  • 建模与优化

    • 使用OR-Tools(Google的一个开源优化工具)来构建和求解线路问题。
    • 路由模型:定义每个车辆的路线,确保所有运输请求按时完成。
    • 约束条件:包括货物的运输时间、距离限制等。
  • 代码实现

    • 数据模型:创建一个包含所有必要数据的模型。
    • 路由索引管理器:管理车辆和节点的索引。
    • 路由模型:定义车辆的路线和运输成本。
    • 运输请求:添加所有需要运输的货物。
    • 优化参数:设置求解的搜索策略,以提高效率。
  • 求解与结果分析

    • 使用指定的搜索参数求解问题。
    • 输出求解结果,包括每辆车的路线和运输距离。
    • 分析总距离和运输效率,确保问题得到最优解。
  • 代码解析

    以下是实现上述逻辑的代码片段:

    from __future__ import print_functionfrom ortools.constraint_solver import routing_enums_pb2from ortools.constraint_solver import pywrapcpdef create_data_model():    data = {}    data['distance_matrix'] = [        [0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354, 468, 776, 662],        [548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674, 1016, 868, 1210],        [776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164, 1130, 788, 1552, 754],        [696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822, 1164, 560, 1358],        [582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708, 1050, 674, 1244],        [274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628, 514, 1050, 708],        [502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856, 514, 1278, 480],        [194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320, 662, 742, 856],        [308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662, 320, 1084, 514],        [194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388, 274, 810, 468],        [536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764, 730, 388, 1152, 354],        [502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114, 308, 650, 274, 844],        [388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194, 536, 388, 730],        [354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0, 342, 422, 536],        [468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536, 342, 0, 764, 194],        [776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274, 388, 422, 764, 0, 798],        [662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730, 536, 194, 798, 0]    ]    data['pickups_deliveries'] = [        [1, 6],        [2, 10],        [4, 3],        [5, 9],        [7, 8],        [15, 11],        [13, 12],        [16, 14]    ]    data['num_vehicles'] = 4    data['depot'] = 0    return datadef print_solution(data, manager, routing, assignment):    total_distance = 0    for vehicle_id in range(data['num_vehicles']):        index = routing.Start(vehicle_id)        plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)        route_distance = 0        while not routing.IsEnd(index):            plan_output += ' {} -> '.format(manager.IndexToNode(index))            previous_index = index            index = assignment.Value(routing.NextVar(index))            route_distance += routing.GetArcCostForVehicle(previous_index, index, vehicle_id)        plan_output += '{}\n'.format(manager.IndexToNode(index))        plan_output += 'Distance of the route: {}m\n'.format(route_distance)        print(plan_output)        total_distance += route_distance    print('Total Distance of all routes: {}m'.format(total_distance))def main():    data = create_data_model()    manager = pywrapcp.RoutingIndexManager(        len(data['distance_matrix']), data['num_vehicles'], data['depot'])    routing = pywrapcp.RoutingModel(manager)    def distance_callback(from_index, to_index):        from_node = manager.IndexToNode(from_index)        to_node = manager.IndexToNode(to_index)        return data['distance_matrix'][from_node][to_node]    transit_callback_index = routing.RegisterTransitCallback(distance_callback)    routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)    dimension_name = 'Distance'    routing.AddDimension(        transit_callback_index, 0, 3000, True, dimension_name)    distance_dimension = routing.GetDimensionOrDie(dimension_name)    distance_dimension.SetGlobalSpanCostCoefficient(100)    for request in data['pickups_deliveries']:        pickup_index = manager.NodeToIndex(request[0])        delivery_index = manager.NodeToIndex(request[1])        routing.AddPickupAndDelivery(pickup_index, delivery_index)        routing.solver().Add(            routing.VehicleVar(pickup_index) == routing.VehicleVar(                delivery_index))        routing.solver().Add(            distance_dimension.CumulVar(pickup_index) <=            distance_dimension.CumulVar(delivery_index))    search_parameters = pywrapcp.DefaultRoutingSearchParameters()    search_parameters.first_solution_strategy = (        routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)    assignment = routing.SolveWithParameters(search_parameters)    if assignment:        print_solution(data, manager, routing, assignment)if __name__ == '__main__':    main()

    总结

    通过上述方法,我们成功实现了Dial-A-Ride问题的求解。代码中定义了问题的数据模型,构建了路由模型,并通过优化算法求解了最优路线。最终输出了每辆车的运输路线和总距离,确保了问题的最优解。

    上一篇:深度学习系列3:框架caffe
    下一篇:图像处理系列1.skimage

    发表评论

    最新留言

    哈哈,博客排版真的漂亮呢~
    [***.90.31.176]2025年04月18日 10时14分31秒