图论-路径优化算法总结

知乎主页icon-default.png?t=LA92https://www.zhihu.com/people/shuang-shou-cha-dai-53

目录

1:Dijkstra算法

1.1:算法思想

1.2:算法步骤

1.3:代码演示

1.4:算法实例

1.4:算法优缺点

2:A* 算法

2.1:算法思想

2.2:算法步骤

2.3:Dijkstras算法与A*算法的比较

3:Floyd算法

3.1:算法思想

3.2:算法步骤

3.3:算法实例

3.4:算法优缺点


1:Dijkstra算法

迪杰斯特拉(Dijkstra)算法是典型的最短路径的算法,用来求得从起始点到其他所有点最短路径(单源最短路径)。该算法采用了贪心的思想,每次都查找与该点距离最近的点,可以看成是广度优先搜索,也因为这样,它不能用来解决存在负权边的图。解决的问题可描述为:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点vs到其余各点的最短路径。

Dijkstra算法就是保证当前节点的值对于前面的层一定是最优的(不管后面有啥只往前看),所以最后到终点的时候,可以保证终点到前一层选一个最优的点,这样从终点到起点一直选当前最小得到的路径一定是最优的。

1.1:算法思想

通过Dijkstra计算图G中的最短路径时,需要指定起点vs(即从顶点vs开始计算)。此外,引进两个集合S和U。S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点vs的距离)。初始时,S中只有起点vs;U中是除vs之外的顶点,并且U中顶点的路径是"起点vs到该顶点的路径"。然后,从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 然后,再从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。重复该操作,直到遍历完所有顶点。

1.2:算法步骤

  • 初始时,S只包含源点,即S={vs},vs的距离为0。U包含除vs外的其他顶点,即U={其余顶点},若u不是vs的出边邻接点,则权值为∞;
  • 从U中选取一个距离vs最小的顶点k,把k加入S中(该选定的距离就是vs到k的最短路径长度min);
  • 以k为新考虑的中间点,修改U中各顶点的距离;若从源点vs到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,即dist[u] = min( dist[u], min + w[k][u] );
  • 重复步骤b和c直到所有顶点都包含在S中。
     

1.3:代码演示

'''
dijkstra algorithm demo
graph size:6*6
node index start from 0
'''
import numpy as np

graph_list = [[0, 2, 1, 4, 5, 1],
              [1, 0, 4, 2, 3, 4],
              [2, 1, 0, 1, 2, 4],
              [3, 5, 2, 0, 3, 3],
              [2, 4, 3, 4, 0, 1],
              [3, 4, 7, 3, 1, 0]]


def dijkstra(graph, src):
    # init
    visited = []
    distance = {src: 0}
    node = list(range(len(graph[0])))
    if src in node:
        node.remove(src)
        visited.append(src)
    else:
        return None
    for i in node:
        distance[i] = graph[src][i]
    prefer = src
    while node:
        _distance = float('inf')
        for i in visited:
            for j in node:
                if graph[i][j] > 0:
                    if _distance > distance[i] + graph[i][j]:
                        _distance = distance[j] = distance[i] + graph[i][j]
                        prefer = j
        visited.append(prefer)
        node.remove(prefer)
    return distance


if __name__ == '__main__':
    distance = dijkstra(graph_list, 0)
    print(distance)

1.4:算法实例

下图是一个无向图,演示Dijkstra的步骤

图论-路径优化算法总结_第1张图片

Dijkstra算法找出以A为起点的单源最短路径计算过程如下:

图论-路径优化算法总结_第2张图片

1.4:算法优缺点

  • 优点:可解释性强,容易理解,可以适用数据量较少的场景。
  • 缺点:时间复杂度高O(n²),计算的是单源最短路径,不是任意两点之间的最短距离;解决不了负权图,有可能出错。

2:A* 算法

2.1:算法思想

A*算法作为Dijkstra算法的扩展,是一种静态路网中求解最短路最有效的方法,在机器人、导航、游戏等领域有着广泛应用。A* 作为 Dijkstra 的改进版,目的就在于解决 Dijkstra 效率低下的问题,上面提到 Dijkstra 算法是计算单源节点到所有节点的距离,即:要遍历所有节点,在不知道目标节点的位置时,它只能向所有可能的方向扩展节点直到发现目标节点为止

A* 算法在 Dijkstra 的基础上引入了启发式函数 h(n),h(n)表示了当前节点到目标节点的成本。保证了最优性的同时,加入了目标节点的信息,提升了搜索效率。

公式表示为:f(n)=g(n)+h(n), 其中f(n) 是节点n从初始点到目标点的估价函数,g(n) 是在状态空间中从初始节点到n节点的实际代价,即起始节点到当前节点的实际代价.
h(n)是从n到目标节点最佳路径的估计代价。即当前节点到目标节点的估计代价。

g(n):对g*(n)的一个估计,是当前的搜索图G中s到n的最优路径费用 g(n)≥g*(n)。

h(n):对h*(n)的估计,是从n到目标节点的估计代价,称为启发函数。

2.2:算法步骤

  • 搜索区域(The Search Area):图中的搜索区域被划分为了简单的二维数组,数组每个元素对应一个小方格,也可以将区域等分成是五角星,矩形等,通常将一个单位的中心点称之为搜索区域节点(Node)。  
  • 开放列表(Open List):我们将路径规划过程中待检测的节点存放于Open List中,而已检测过的格子则存放于Close List中。
  • 父节点(parent):在路径规划中用于回溯的节点,开发时可考虑为双向链表结构中的父结点指针。
  • 路径排序(Path Sorting):具体往哪个节点移动由以下公式确定:F(n) = G + H 。G代表的是从初始位置A沿着已生成的路径到指定待检测格子的移动开销。H指定待测格子到目标节点B的估计移动开销。
  • 启发函数(Heuristics Function):H为启发函数,也被认为是一种试探,由于在找到唯一路径前,我们不确定在前面会出现什么障碍物,因此用了一种计算H的算法,具体根据实际场景决定。在我们简化的模型中,H采用的是传统的曼哈顿距离(Manhattan Distance),也就是横纵向走的距离之和。

下面为Dijkstra 算法(没有用到启发式策略)动画演示,其中{ 绿色:起点    红色:终点     黑色:障碍物     白色:路径     黄色:已处理的节点 }

图论-路径优化算法总结_第3张图片

下面是A* 算法的动画演示(使用了启发式信息:到目标的距离)

图论-路径优化算法总结_第4张图片

与Dijkstra 算法相比,A* 算法由于引入了启发函数 h(n),所以它拓展节点的时候具有一定目的性(即向目标节点的方向扩展),所以它搜索目标节点时所需要扩展的中间节点更少,因此算法效率更高。

2.3:Dijkstras算法与A*算法的比较

  1. Dijkstra算法计算源点到其他所有点的最短路径长度,A*关注点到点的最短路径(包括具体路径)。
  2. Dijkstra算法建立在较为抽象的图论层面,A*算法可以更轻松地用在诸如游戏地图寻路中。
  3. Dijkstra算法的实质是广度优先搜索,是一种发散式的搜索,所以空间复杂度和时间复杂度都比较高。对路径上的当前点,A*算法不但记录其到源点的代价,还计算当前点到目标点的期望代价,是一种启发式算法,也可以认为是一种深度优先的算法。

3:Floyd算法

Floyd算法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。简单的说就是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd算法的时间复杂度为O(N3),空间复杂度为O(N2)。

3.1:算法思想

Floyd算法定义了两个二维矩阵:

  1. 矩阵D记录顶点间的最小路径 
    例如D[0][3]= 10,说明顶点0 到 3 的最短路径为10;
  2. 矩阵P记录顶点间最小路径中的中转点 
    例如P[0][3]= 1 说明,0 到 3的最短路径轨迹为:0 -> 1 -> 3。

它通过3重循环,k为中转点,v为起点,w为终点,循环比较D[v][w] 和 D[v][k] + D[k][w] 最小值,如果D[v][k] + D[k][w] 为更小值,则把D[v][k] + D[k][w] 覆盖保存在D[v][w]中。

3.2:算法步骤

3.3:算法实例

上述概念理解起来比较晦涩,直接以一个图例中的最短路径来说明Floyd算法步骤:

图论-路径优化算法总结_第5张图片

3.4:算法优缺点

优点:容易理解,可以算出任意两个节点之间最短距离的算法,程序容易写;

缺点:复杂度达到三次方,不适合计算大量数据,它需要用邻接矩阵来储存边,这个算法通过考虑最佳子路径来得到最佳路径。注意单独一条边的路径也不一定是最佳路径。

知乎主页https://www.zhihu.com/people/shuang-shou-cha-dai-53icon-default.png?t=LA92https://www.zhihu.com/people/shuang-shou-cha-dai-53

你可能感兴趣的:(图论及图深度学习,算法,图论)