【转载】SPFA最短路算法解析

来源:互联网 发布:中国网络教育大学 编辑:程序博客网 时间:2024/06/05 08:34
SPFA是一个比较高效的算法,虽说在比较大的数据时仍然无法比Dijkestra+Heap快,但是代码却很简单,以我的水平而言,代码要短上一倍以上。SPFA这个算法的实用性比较强,所以在OI中是一个相当不错的算法。
SPFA是Bellman-Ford算法的常数优化,如果再加上LLL优化和SLF优化,就更加强大了。下面,我们来剖析其本质:
【SPFA的定义】
SPFA的定义和Bellman-Ford的很像,首先,Bellman-Ford的定义是每一轮都对于每一个点进行所谓的“松弛”操作,用另一种方法来讲就是用能够到达当前点的最短路来更新所有的临近点。而SPFA的优化,则是注意到了不一定要对每一个点进行这样的操作,而只需要对于更新了的点。也就是说,SPFA的算法描述大概是这样的:首先将除了起点外到其他所有点的最短路径全部设为INF,即无穷大,然后将起点放入队列,每一次只对队列的头元素进行“松弛”操作,然后将该操作所能够更新到的点全部插入队列尾部,并将队列头元素弹出。而这,就是SPFA。
其实SPFA的真实情况比这还要简单,根据杨鸿飞所说的那样,这SPFA就是一个能够将一个点多次入队的广搜!想想看,这个广搜,不就是每一次将能够更新的点加入队列吗?或者说这也是一种迭代,每一次不断地更新那些能够更新的点,并将新的能够更新的点继续更新,直到完全无法更新为止,或者说,就是上面的那个“广搜”的队列完全为空为止。

【SPFA的框架】
既然都说了SPFA是一个最短路径算法,那应用的前景也很广泛了。但是,有一点要注意:SPFA很可能要使用循环队列!因为SPFA中的点会多次入队,很难估计实际所会使用的队列大小,所以应该在有一定空间赋予的情况下,使用循环队列,避免出现“假溢出”之类的问题。
SPFA的框架很简单,如果不考虑循环队列的话,就是这样:

1.将所有点到起点的最短距离全部置为无穷大

2.将起点到自己的距离设为0

3.将起点放入队列中

4.用当前队列的头结点去更新其的邻近的节点

5.将能够更新的节点入队列

6.弹出当前队列的头结点,如果队列为空,跳到7,否则跳到4

7.最后将相应的最短路径输出

至于循环队列,也同样简单。
我觉得最简单的方法,也最不容易出错的方法,是先写一个不用循环队列的SPFA,然后再将所有的关于访问队列数组的地方,全部在下标后面模一下队列数组的大小即可。虽说模运算比较慢,但是这样不容易写错,而且一开始没有用循环队列的时候还易于调试。
0 0
原创粉丝点击