介绍
最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。
算法具体的形式包括:
- 确定起点的最短路径问题 - 即已知起始结点,求最短路径的问题。
- 确定终点的最短路径问题 - 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。
在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。 - 确定起点终点的最短路径问题 - 即已知起点和终点,求两结点之间的最短路径。
- 全局最短路径问题 - 求图中所有的最短路径。
用于解决最短路径问题的算法被称做“最短路径算法”。
单源最短路径
SPFA
算法大致流程 是用一个队列来进行维护。
初始时将源点加入队列,每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队,直到队列为空时算法结束。
SPFA算法(Shortest Path Faster Algorithm),也是求解单源最短路径问题的一种算法,用来解决的问题如下:
给定一个加权有向图G和源点s,对于图G中的任意一点v,求从s到v的最短路径。
SPFA算法是 Bellman-Ford 算法的一种队列实现,减少了冗余计算,他的基本算法和 Bellman-Ford 一样,并用如下方法改进:
第一步,不是枚举所有节点,而是通过队列来进行优化,设置一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值 对 离开u点所指向的结点v 进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。
同时,除了通过判断队列是否为空来结束循环,还可以通过下面的方法:即判断有无负环,如果某个点进入队列的次数超过V次,则存在负环(SPFA算法无法处理带负环的图)。
SPFA 在形式上和 BFS(广度优先搜索)非常类似,不同的是:在广度优先搜索中,一个点出了队列就不可能重新进入队列,但是SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身被改进,于是再次用来改进其它的点,这样反复迭代下去。设一个点用来作为迭代点对其它点进行改进的平均次数为k,有办法证明对于通常的情况,k在2左右。
然而在实际的应用中SPFA算法的时间效率不是很稳定,为了避免最坏情况的出现,通常使用时间效率更加稳定的Dijkstra算法。
SPFA模板
1 | //gh[][]为有向图(gh[i][j]为结点i到结点j的权值,如果gh[i][j]不存在,则为-1) |
任意两点最短路径
使用条件&范围:通常可以在任何图中使用,包括有向图、带负权边的图。
Floyd-Warshall 算法用来找出每对点之间的最短距离。它需要用邻接矩阵来储存边,这个算法通过考虑最佳子路径来得到最佳路径。
注意单独一条边的路径也不一定是最佳路径。
- 从任意一条单边路径开始。所有两点之间的距离是边的权,或者无穷大,如果两点之间没有边相连。
- 对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。
- 不可思议的是,只要按排适当,就能得到结果。
1 | // dist(i,j) 为从节点i到节点j的最短距离 |
Reference
http://www.nocow.cn/index.php/SPFA%E7%AE%97%E6%B3%95s
http://www.nocow.cn/index.php/Floyd-Warshall%E7%AE%97%E6%B3%95