弗洛伊德算法求出最短距离_自动驾驶路径规划-Dijkstra算法

80ae376e141cfb890a03ab8782af7da1.png

《自动驾驶路径规划-Graph-Based的BFS最短路径规划》中提到我们可以将地图抽象为Graph的数据结构,然后利用Graph的广度优先遍历算法(Breadth-First Search, BFS)解决无权重的High-Level的地图级别的规划。但是实际应用场景中,地图中各个路径所代表的Graph的边的权重都是不同的,比如距离长的Edge权重就应该比较低;交通拥堵的Edge权重就应该低等等。对于有权重的Graph如何进行最短路径规划呢,Dijkstra算法可以解决这个问题。

b3c60e968b3fa978cffa75e7c4584f44.png
图片来源:http://www.csie.ntnu.edu.tw/~u91029/Circuit.html

1、什么是Dijkstra算法

Dijkstra算法是一种有权图(Graph)的单源最短路径求解算法,给定一个起点,使用Dijkstra算法可以得到起点到其它所有节点的最短路径。Dijkstra算法要求图(Graph)中所有边的权重都为非负值,只有保证了这个条件才能该算法的适用性和正确性。

2、Dijkstra算法Overview

假设有权图(Graph)的如下,起点(Starting Node)为0,我们一步步看看如何使用Diskstra算法计算起点(Starting Node)到达所有其它Node的最短路径。

1ee6866529cb2dcf976a081fc4199c09.png

首先我们需要定义一个数据结构来记录起点(Starting Node)到其它所有Node的最短距离,并将所有最短距离的值初始化为正的无穷大,表示各个节点(Node)均不可达。

dist = [infinity, infinity, ..., infinity]

然后,需要定义一个(index, distance)的Pair对象来存储起点(Starting Node)到index Node的当前最短距离,其中index为顶点的索引,distance为index Node到Starting Node的最短距离。在开始进行路径搜索前,所有Node对应的最短距离都初始化为正的无穷大。

2ce56fe9e54db588ca5508dd74513438.png

在图的路径搜索过程中,我们需要先搜索距离最近的节点,所以我们需要使用优先级队列(Priority Queue)或者小顶堆(Min Heap)的数据结构来存储(index, distance)的Pair,保证每次取出的待访问Node都是距离起点(Starting Node)最近的Node。

准备好数据结构之后,开始算法执行过程:

1、首先将起点(Starting Node)=(0, 0)放入优先级队列(Priority Queue),表明我们从index=0的节点开始查找,该节点距离起点(Starting Node)的distance = 0;

8ec48122d44ff050e73a1021dc2311b0.png

此时优先级队列(Priority Queue)的内容如下:

def55b2f08a5792a48096281ab83f61d.png

2、从优先级队列(Priority Queue)中取出distance最小的Node(此时index=0的Node的distance最小),遍历它的所有Neighbor节点。

首先遍历index=1的Node,该Node未被访问过,所以直接更新起点(Starting Node)到index = 1的Node的最短距离为4,并且放入到优先级队列中(Priority Queue)中;

然后遍历index=4的Node,该Node未被访问过,所以直接更新Starting Node到index=2的最短距离为1,并且放入到优先级队列中(Priority Queue)中;

881e268c692b7077aa1488b09d85ea04.png

此时优先级队列(Priority Queue)的内容如下:

3d6bfadb3550791833df89728cdb88fd.png

3、从优先级队列(Priority Queue)中取出distance最小的Node(此时index=2的Node的distance最小),遍历它的所有Neighbor节点。

首先遍历index=1的Node,由于index=1的Node已经被访问过,此时需要比较当前的距离是否小于已有的距离。起点(Starting Node)到index =1的distance为1 + 2 =3,小于已有的起点(Starting Node)直接到index=1的Node的distance = 4,因此更新起点(Starting Node)到index=1的distance为3。

然后遍历index=3的Node,该Node未被访问过,所以直接更新其到起点(Starting Node)的distance为1+ 5 = 6。

80b134088e04fb80143bdae1a6dc29be.png

此时优先级队列(Priority Queue)的内容如下:

0893a8ed041523ccc1d23691c836eebc.png

4、从优先级队列(Priority Queue)中取出距离最小的Node(此时index=1的Node的distance最小),遍历它的所有Neighbor节点。

遍历index=3的Node,起点(Starting Node)到index=3的Node距离为3 + 1 = 4,小于原有起点(Starting Node)经由index=2的到达index=3的Node的距离6,所以从更新起点(Starting Node)到index=3的Node的最短距离为4。

f273b9ec5d8c610f0b8d76e06e528881.png

此时优先级队列(Priority Queue)的内容如下:

acc5f94a1715385e76893aced40ba46b.png

5、从优先级队列(Priority Queue)中取出距离最小的Node(此时index=3的Node的distance最小),遍历它的所有Neighbor节点。

遍历到index=4的Node,该Node尚未被遍历过,起点(Starting Node)到index=4的Node最短距离为4 + 3 = 7;。

f678789d78a88d3617491106264eb1af.png

此时优先级队列(Priority Queue)的内容如下:

dd1275e5ea061b2967a117ab9874ccd0.png

这就是Dijkstra算法的完整执行过程,至此我们得到了从起点(Starting Node)到所有其它Node的最短距离。

3、Dijkstra算法实现路径查找

因为我们的目标是搜索从起点到目的地的最短路径,而Dijkstra算法提供了从起点(Starting Node)到其它所有节点的最短路径,所以我们在路径查找中对Dijkstra算法做了剪枝处理

def extractPath(self, u, pred):
    path = []
    k = u
    path.append(k)
    while k in pred:
        path.append(pred[k])
        k = pred[k]
    path.reverse()
    return path
def findShortestPathInWeightGraph(self, start, end): 
    # Mark all the vertices as not visited 
    closed = set()

    pq = queue.PriorityQueue()
    pred = {} 
    min_dist = {}
    pq.put((0,start)) 
    min_dist["0"] = 0

    while pq.qsize() != 0: 
        dist, u = pq.get()
        closed.add(u)

        if u == end:
            path = self.extractPath(u, pred)
            return path

        for to_node, to_weight in self.__graph_dict[u].items(): 
            if to_node in closed:
                continue;
            newdist = dist + to_weight
            if to_node in min_dist:
                if newdist < min_dist[to_node] :
                   min_dist[to_node] = newdist
                   pred[to_node] = u
            else:
                min_dist[to_node] = newdist
                pred[to_node] = u
                pq.put((newdist, to_node))

构造如图2.1的Graph,测试代码如下:

g = { "0" : {"1":4, "2":1},
      "2" : {"1":2, "3":5},
      "1" : {"3":1},
      "3" : {"4":3}
    }

graph = Graph(g)

print('The path from vertex "0" to vertex "3":')
path = graph.findShortestPathInWeightGraph("0", "3")

print(path)

路径检索结果如下:

The path from vertex "0" to vertex "3":
['0', '2', '1', '3']

作为运动规划领域最著名的算法之一,Dijkstra算法可以解决带权重有向图的最短路径规划问题,在实际的路径规划中也有大规模的实际应用。但是Dijkstra算法的搜索没有方向性,会有大量冗余的搜索操作。我们可以给Dijkstra加上一些启发性的信息,引导搜索算法快速的搜索到目标,这就是A*算法。

由于加入引导信息,A*算法在大多数情况下会比Dijkstra算法要快。

586fb602888afc437e71a1d17cc82b4b.png
Dijkstra和A*算法演示

参考链接

1、[运动规划-简介篇](运动规划 | 简介篇)

2、Dijkstra's Shortest Path Algorithm | Graph Theory

注:本文首发于微信公众号,转载请注明出处,谢谢!

80367718979c4a1b3d0b53f85e66549e.png
公众号:半杯茶的小酒杯

个人博客地址:

http://www.banbeichadexiaojiubei.com​www.banbeichadexiaojiubei.com

推荐阅读:

半杯茶的小酒杯:自动驾驶路径规划-Graph Based的BFS最短路径规划​zhuanlan.zhihu.com
08a351944ceaf0f91bb58c1ce1f94ff3.png
半杯茶的小酒杯:自动驾驶运动规划-Dubins曲线​zhuanlan.zhihu.com
7bfd94cf7f2743c46f83c48318a7136a.png
半杯茶的小酒杯:未知环境下的Lidar概率占位栅格图(Occupancy Grid Map) Python代码实现​zhuanlan.zhihu.com
815539fa34885cc95c50f3dce912aa41.png
半杯茶的小酒杯:自动驾驶Mapping-占位栅格图(Occupancy Grid Map)​zhuanlan.zhihu.com
50a504e4bc38e95e296bb16aaed06f7e.png
半杯茶的小酒杯:自动驾驶中的车辆运动学模型​zhuanlan.zhihu.com
87ea5c336fb600f29bb1a357a35ddae9.png
半杯茶的小酒杯:自动驾驶定位算法(十五)基于多传感器融合的状态估计(muti-Sensors Fusion)​zhuanlan.zhihu.com
7b4d1d5ce4d93f49598e812ec5593d6a.png
自动驾驶路径规划器-Lattice Planner详解​www.banbeichadexiaojiubei.com
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Dijkstra算法是一种用于解决单源最短路径问题的算法。它的基本思想是从起点开始,逐步扩展到其他节点,每次选择当前距离起点最近的节点,并更新与该节点相邻的节点的距离。通过这种方式,可以找到起点到其他节点的最短路径Dijkstra算法的时间复杂度为O(n^2),但是可以通过使用堆优化来将其优化到O(nlogn)。 ### 回答2: Dijkstra算法是一种解决单源最短路径问题的贪心算法,其思想是利用“松弛”操作来不断更新当前点到源点的最短距离,但前提是所有边的权重非负。如果有负权边,则需要使用Bellman-Ford算法。 首先,我们需要定义一个数组dis数组,用于存储源点s到各个点的最短距离。dis[s]初始为0,其他点初始为无限大。接着,我们需要维护一个集合S,表示已经求出最短路径的点的集合。将源点s加入集合S中。 对于每个未加入S的点v,我们通过选择其它点到源点s的最短路径中的一个点u,然后将dis[v]更新为dis[u] + w(u,v),其中w(u,v)表示边(u,v)的权重。具体地,这个操作称为“松弛”操作。 在松弛操作中,我们需要比较dis[u] + w(u,v)和dis[v]的大小,如果前者更小,则更新dis[v]的值为dis[u] + w(u,v)。 重复执行以上操作,直到所有的点都加入到集合S中。最后dis数组中存储的就是源点s到所有点的最短距离Dijkstra算法可以用堆优化,时间复杂度为O(mlogn),其中n表示图中的点数,m表示边数。Dijkstra算法也可以应用于稠密图,时间复杂度为O(n^2)。 总之,Dijkstra算法是一种经典的求解单源最短路径问题的算法,其实现简单,效率高,被广泛应用于路由算法和图像处理等领域。 ### 回答3: Dijkstra算法是一种在加权有向图中寻找从源节点到其他节点的最短路径的贪心算法。该算法基于其它路径加权节点的已知最短路径去更新更长路径的信息直到找到从源节点到目标节点的最短路径。在整个计算过程中,Dijkstra算法需要维护一个待处理节点集合和一个距离源节点的最短路径数组。 算法的具体实现如下: 1. 初始化源节点及其距离为0,其他节点的距离为无穷大。 2. 将源节点加入到待处理节点集合中。 3. 对于源节点的所有相邻节点,更新它们距离源节点的最短路径。如果当前路径小于之前已知的最短路径,则更新最短路径数组。 4. 遍历待处理节点集合中除源节点外的节点,选择距离最近的节点作为当前节点,并将它从待处理机集合中移除。 5. 对于当前节点的所有相邻节点,更新它们距离源节点的最短路径。如果当前路径小于之前已知的最短路径,则更新最短路径数组。 6. 重复步骤4和5,直到待处理节点集合为空或者目标节点已经被遍历Dijkstra算法的时间复杂度为O(n^2),其中n为节点数,由于它是贪心算法,只能处理非负权重的图,否则可能会陷入死循环。但是,Dijkstra算法是单源最短路径问题的最优解,因此在处理小规模的图时效果很好。在处理大规模图时,需要使用其他高效的算法,如A*算法、Bellman-Ford算法等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值