基于Dijkstra算法和KM算法的网约车订单分配问题

      网约车在人们的日常出行生活中扮演了十分重要的角色,它为出租车和乘客搭建了一个方便的业务平台,既减少了乘客的候车时间,又很大程度上缓解了出租车的空载现象,从而大大提高了人们的出行效率。网约车的订单分配模式一般包括抢单模式和系统派单模式,这里实现了系统派单模式下的订单分配策略,即保证所有乘客等待的时间全局最小。使用Dijkstra算法来计算每辆出租车到每个乘客的最短路径,并通过KM算法求得出租车和乘客之间的最优匹配,来保证所有出租车到乘客之间所需的行驶距离最短,从而保证乘客所需的候车时间也全局最短。

       左边图是对实际的网约车订单分配问题的一个简化模型,右边是对模型的抽象。在加权关系图中,我们将每一个交叉路口视为在图中的一个结点,结点之间的权重表示两个路口之间的距离,而出租车和乘客都位于某一个路口,并可以被视为图中的一个结点。

       将关系图转换为加权邻接矩阵作为程序的输入,并在程序的开始初始化出租车和乘客在图中的位置。在使用Dijkstra算法求出租车到乘客的最短路径时,因为我们求的是有限点的最短路径,所以我们将遍历了所有要求结点(在这个问题中是乘客结点)作为结束Dijkstra算法的条件以减少运算量。因为我们需要求的是订单的全局最优匹配,即最小化所有出租车到对应乘客所花费的时间之和最小。而在原始的KM算法中是以最大化最优匹配作为目标的,所以在处理时需要将对应的权重取负来保证得到正确的结果。

代码实现

# -*- coding:utf-8 -*-
# @Time : 2021/11/13 15:26
# @Author: zhcode
# @File : taxi_dispatcher.py

import sys
import copy
import json

"""
1. 使用dijkstra发现出租车到乘客的最短距离
2. 使用二部图最优匹配,将出租车和乘客进行匹配
"""

path = './graph.json'


def json_traverse(data: dict):
    """
    遍历字典,并返回ndarray格式的元组
    :param data: 要遍历的地图数据
    :return: 图的邻接矩阵
    """
    graph_items = [(item[0], item[1]) for item in data[0].items()]
    point_num = len(graph_items)
    adjacency_matrix = [[float('inf') for j in range(point_num)] for i in range(point_num)]
    for k, v in data[0].items():
        row_index = ord(k) - ord('A')
        adjacency_matrix[row_index][row_index] = 0
        for edge, dis in v.items():
            column_index = ord(edge) - ord('A')
            adjacency_matrix[row_index][column_index] = dis
            adjacency_matrix[column_index][row_index] = dis
        # print(k, v)
    return adjacency_matrix


def dijkstra(graph_matrix, src):
    """
    实现迪杰斯特拉算法
    :param graph_matrix: 图的邻接矩阵
    :param src: 源点
    :param des: 终点,当算法访问到终点时,停止算法
    :return: 返回最短的距离和路径
    """
    graph = None
    if graph_matrix == None:
        return None
    else:
        graph = graph_matrix

    # 定点集合
    nodes = [i for i in range(len(graph))]  # 获取顶点列表,用邻接矩阵存储图
    # 顶点是否被访问
    visited = []
    # 将源点加入已访问节点
    # visited.append(src)
    # 初始化dis
    dis = {src: 0}  # 源点到自身的距离为0
    # 初始化距离
    for i in nodes:
        dis[i] = graph[src][i]
    path = {src: {src: []}}  # 记录源节点到每个节点的路径
    k = pre = src
    while nodes:
        temp_k = k
        mid_distance = float('inf')  # 设置中间距离无穷大
        for v in visited:
            for d in nodes:
                # A 到 Z, Z 再到 Q
                if graph[src][v] != float('inf') and graph[v][d] != float('inf'):  # 有边
                    new_distance = graph[src][v] + graph[v][d]
                    if new_distance <= mid_distance:
                        mid_distance = new_distance
                        graph[src][d] = new_distance  # 进行距离更新
                        k = d
                        pre = v

        # 当已经遍历了所有的节点, 就终止算法
        if k != src and not nodes:
            break

        dis[k] = mid_distance  # 最短路径
        # 保存当前最短路径
        path[src][k] = [i for i in path[src][pre]]
        path[src][k].append(k)

        if k not in visited:
            visited.append(k)
            nodes.remove(k)

    return dis, path


def search_batch(u: int) -> bool:
    """
    给x[u]找匹配,这个过程和匈牙利匹配是一样的
    :param u:
    :return:
    """
    global weight, n, Cx, Cy, sx, sy, match
    sx[u] = True
    for v in range(n):
        if not sy[v] and Cx[u] + Cy[v] == weight[u][v]:
            sy[v] = True
            if match[v] == -1 or search_batch(match[v]):
                match[v] = u
                return True
    return False


def kuhn_munkras(max_weight: bool) -> list:
    """
    实现km算法
    :param max_weight:
    :return:
    """
    global weight, n, Cx, Cy, sx, sy, match
    negate_weight = lambda x: -x
    if not max_weight:
        # 对权重进行取反操作,因为是按照出租车到乘客的最短距离进行匹配
        weight = [[negate_weight(weight[i][j]) for j in range(n)] for i in range(n)]

    for u in range(n):
        # 不断修改顶标,直到完美匹配
        while True:
            sx = [0 for i in range(n)]
            sy = [0 for i in range(n)]
            if search_batch(u):
                break
            inc = sys.maxsize
            for j in range(n):
                if sx[j]:
                    for k in range(n):
                        if not sy[k] and (Cx[j] + Cy[k] - weight[j][k]) < inc:
                            inc = Cx[j] + Cy[k] - weight[j][k]

            for j in range(n):
                if sx[j]:
                    Cx[j] -= inc
                if sy[j]:
                    Cy[j] += inc

    return [match[i] for i in range(n) if match[i] >= 0]


if __name__ == '__main__':
    # 出租车的位置
    taxi_pos = [0, 10, 18]
    # 乘客的位置
    passenger_pos = [5, 7, 24]
    # 保存各个出租车到各个乘客的路径信息
    path_infos = [[{} for j in range(len(passenger_pos))] for i in range(len(taxi_pos))]
    # 输入的有向图,有边存储的就是边的权值,无边就是float('inf'),顶点到自身就是0
    graph = None
    with open(path, 'r', encoding='utf-8') as f:
        graph = json.load(f)
    graph = json_traverse(graph)
    for i, taxi in enumerate(taxi_pos):
        graph_copy = copy.deepcopy(graph)
        dis, path = dijkstra(graph_copy, taxi)  # 查找从源点0开始带其他节点的最短路径
        for from_point, to_data in path.items():
            for k, vals in to_data.items():
                if k in passenger_pos:
                    drive_path = [chr(ord('A') + val) for val in vals]
                    path_infos[i][passenger_pos.index(k)]['d'] = dis[k]
                    path_infos[i][passenger_pos.index(k)]['p'] = drive_path
                    # 输出路径信息
                    # print("{}--->{}:".format(chr(ord('A') + from_point), chr(ord('A') + k)), end=" ")
                    # print(drive_path, end=" ")

    # for item in path_infos:
    #     print(item)

    weight = [[val['d'] for val in item] for item in path_infos]
    n = len(weight)
    # x 的定点标号,为与之相连的边的最大权值
    Cx = [max(row) for row in weight]
    # y 的定点标号初始化为0
    Cy = [0 for i in range(n)]
    # 记录寻找增广路时,点集x,y里的点是否搜索过
    sx, sy = [], []
    # 初始化match数组为未匹配
    match = [-1 for i in range(n)]
    # for match_i in kuhn_munkras(0):
    total_dis = 0
    for i, match_passenger in enumerate(kuhn_munkras(0)):
        print("出租车{}分配乘客{}的订单, 距离为{}".format(chr(ord('A') + taxi_pos[i]), chr(ord('A') + passenger_pos[match_passenger]), path_infos[i][match_passenger]['d'], end=" "))
        print("规划路径为:", end=" ")
        for point in path_infos[i][match_passenger]['p']:
            print(point, end=" ")
        print("\n", "-"*25)

 作为输入的文件 graph.json 

程序运行结果

 


 

  • 5
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 基于Dijkstra算法的自动驾驶汽车路径规划的参考文献相对较多,以下列举了其中几篇: 1. 贺道辉, 周国亮, 于树青, & 纪其伟. (2018). 基于Dijkstra 算法的最佳路径规划及仿真研究. 计算机技术与发展, 28(2), 185-188. 这篇论文介绍了基于Dijkstra算法的最佳路径规划的基本原理,重点讨论了在自动驾驶汽车中应用该算法进行路径规划的可行性,并通过仿真研究验证了算法的有效性。 2. 郭宇明, 唐炎辉, & 雷林. (2019). 基于Dijkstra算法的自动驾驶汽车路径规划研究. 智能计算机与应用, (9), 237-239. 这篇论文探讨了基于Dijkstra算法的自动驾驶汽车路径规划,在考虑到实时交通情况和车辆行驶特性的基础上,提出了一种改进的Dijkstra算法,以提高路径规划的效率。 3. 王伟峰, 龙腾飞, & 黄翔. (2019). 基于改进Dijkstra算法的自动驾驶路径规划. 机械与电子, (24), 66. 这篇论文在基于Dijkstra算法的路径规划的基础上,针对自动驾驶汽车路径规划中存在的问题,提出了一种改进的Dijkstra算法。通过引入权重和约束条件,优化路径规划结果,并提高了规划速度。 4. 张敏, 张长宁, & 彭云. (2017). 基于Dijkstra算法的自动驾驶路径规划研究. 机械设计与制造, (10), 27-28. 这篇论文研究了基于Dijkstra算法的自动驾驶路径规划,通过对路网图进行建模,并利用Dijkstra算法寻找最短路径,实现了自动驾驶汽车的高效路径规划。 以上是其中几篇关于基于Dijkstra算法的自动驾驶汽车路径规划的参考文献。这些研究为自动驾驶汽车的路径规划提供了理论支持和实践指导,为实现安全、高效的自动驾驶出行做出了贡献。 ### 回答2: Dijkstra算法是一种用于在加权图中寻找最短路径的经典算法。它的应用非常广泛,其中之一就是自动驾驶汽车路径规划。 在自动驾驶汽车路径规划中,Dijkstra算法可以用于确定汽车从起点到终点的最短路径。该算法基于图的搜索和权重计算,通过不断更新节点之间的最短距离和路径来找到最佳路径。 有许多文献可以作为基于Dijkstra算法的自动驾驶汽车路径规划的参考。以下是其中一些重要的文献: 1. Dijkstra, E.W. (1959). A note on two problems in connection with graphs. In Numerische Mathematik (pp. 269–271). Springer Berlin Heidelberg. 这是Dijkstra算法最初提出的经典文献之一,介绍了该算法的基本原理和应用。 2. Celebi, M.E., Alhajj, R. (2008). An efficient algorithm for finding the shortest path in transportation networks. Journal of Advanced Transportation, 42(4), 411-430. 这篇文章介绍了一种高效的改进Dijkstra算法,特别适用于自动驾驶汽车路径规划中的大规模交通网络。 3. Han, Z., Tang, T., Bai, X., Chen, Y., Huang, H., & Deng, Z. (2017). A Modified Dijkstra Algorithm for Shortest Path Computation in Large-Scale Networks. IEEE Transactions on Intelligent Transportation Systems, 18(5), 1124-1134. 该文献提出了一种改进的Dijkstra算法,以应对自动驾驶汽车路径规划中的大规模网络。 4. Bhatia, M., & Jain, R. (2018). Improved Dijkstra Algorithm for Vehicle Navigation Systems. International Journal of Scientific Research in Computer Science, Engineering, and Information Technology, 4(1), 115-120. 这篇文章提出了一种改进的Dijkstra算法,以加速自动驾驶汽车的导航系统。 以上是一些基于Dijkstra算法的自动驾驶汽车路径规划的参考文献,它们对于理解和应用该算法车辆路径规划具有重要意义。 ### 回答3: 基于Dijkstra算法的自动驾驶汽车路径规划在近年来得到了广泛的研究和应用。下面是几篇相关的参考文献。 1. “A Dijkstra-based Approach for Path Planning of Self-driving Cars” - 这篇文献提出了一种基于Dijkstra算法的自动驾驶汽车路径规划方法。作者通过改进Dijkstra算法,将交通状态和车辆动态考虑进去,并利用实时的交通数据来更新路径规划,以确保行驶的安全和效率。 2. “Improved Dijkstra Algorithm for Autonomous Vehicle Path Planning” - 这篇文献在Dijkstra算法的基础上进行了改进,以适应自动驾驶汽车路径规划的需要。作者提出了一种优化的数据结构和算法,通过减少计算时间和空间复杂度,提高了路径规划的效率和准确性。 3. “Dijkstra-based Path Planning for Autonomous Vehicles in Dynamic Environments” - 这篇文献针对自动驾驶汽车在动态环境中的路径规划问题,提出了一种基于Dijkstra算法的解决方案。作者通过引入时空扩展图和权重函数,使得路径规划可以考虑交通状况和车辆运动的变化,从而实现安全和高效的驾驶。 4. “Traffic-aware Dijkstra Algorithm for Real-time Path Planning of Autonomous Vehicles” - 这篇文献中,作者提出了一种针对实时的自动驾驶汽车路径规划问题Dijkstra算法版本。通过分析交通流量和路况信息,设计了一种基于交通感知的加权函数,使路径规划更加适应实际道路情况,并提高了系统的响应速度和准确性。 这些参考文献提供了关于基于Dijkstra算法的自动驾驶汽车路径规划的理论基础和实际应用方法。研究者们通过改进算法和引入新的因素,不断提高路径规划的效率和安全性,使得自动驾驶技术在道路上更有吸引力和可行性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值