最短路
2015-10-30 16:01
281 查看
最短路问题包括:单源最短路、每两点最短路。
一、单源最短路:Dijkstra算法、Bellman-Ford算法、SPFA算法
1、Dijkstra算法 --- 只能处理正边权图
(1) 原始Dijkstra算法:O(n^2)。
(2) 使用优先队列优化的Dijkstra算法:O(E*logE):
想象成从源点有一水柱喷涌而出,水流经过若干条带权的边后(权值越大,流经时间越长),整张地图分成有水部分和无水部分,从有水部分中选取一个距离源点最短的点(当然这个点需要从来没有被选取过),以这个点为中心,水流又流向其它无水部分节点,如此不断更新地图。这里的“从有水部分中选取一个距离源点最短的点”需要用到优先队列。
2、Bellman-Ford算法:O(VE) --- 优点:可以处理负边权图
负环定义:一个环路中所有路径的权值之和为负,称为负环。
伪代码 Start
(初始化)起点距离:0,其他点距离:INF // 不能太大,防止溢出
for n = [1 ~ N) //最多做n-1次,如果做了n-1次之后还有点的距离没更新,那么说明图存在负环。
for e = [1 ~ E]
d[e.v] = min ( d[e.v] , d[e.u] + cost[e] ) //称为松弛操作
for e = [1 ~ E]
if ( d[e.v] > d[e.u] + cost[e] ) return false; //存在负环
return true; //不存在负环
伪代码 End
3、SPFA算法:O(kE) --- 基于Bellman-Ford算法优化,可以处理负边图,并且复杂度较小
用一个先进先出的队列维护,先计算每个点的估计距离,如果发现这个值能再次更新,那么把它重新加入队列,以便检查它相邻的点。
伪代码 Start
(1)(初始化)起点距离:0,其他点距离:INF,新建队列que:推入起点。
(2) 从队首取出top,标记top已出队(负环检查:同时对top出队次数进行检查,如果大于n,说明出现负环,算法结束)。遍历top所连的边e,如果e.to可以更新,那么更新e.to,检查e.to是否在队列中,如果不在加入队列中。
(3) 重复步骤2,直到队列为空。
伪代码 End
二、每两点最短路:Floyd算法 --- 图可以是有向图或者无向图,可以存在负边,但是不能存在负环。
伪代码 Start
(初始化)d[i][i]:0,其他两点间距离:INF //不能太大,防止下文 d[i][k] + d[k][j] 溢出
for k = [0,n)
for i = [0,n)
for j = [0,n)
d[i][j] = min( d[i][j] , d[i][k] + d[k][j] ); //可以加个pre数组,同时记录路径。
伪代码 End
Floyd算法中边权可正可负,只要图中不存在负环都可以得出正确答案。关于Floyd算法的负环判定,见:Floyd求最小环,只要求出的最小环是正的,就不存在负环。
一、单源最短路:Dijkstra算法、Bellman-Ford算法、SPFA算法
1、Dijkstra算法 --- 只能处理正边权图
(1) 原始Dijkstra算法:O(n^2)。
(2) 使用优先队列优化的Dijkstra算法:O(E*logE):
想象成从源点有一水柱喷涌而出,水流经过若干条带权的边后(权值越大,流经时间越长),整张地图分成有水部分和无水部分,从有水部分中选取一个距离源点最短的点(当然这个点需要从来没有被选取过),以这个点为中心,水流又流向其它无水部分节点,如此不断更新地图。这里的“从有水部分中选取一个距离源点最短的点”需要用到优先队列。
2、Bellman-Ford算法:O(VE) --- 优点:可以处理负边权图
负环定义:一个环路中所有路径的权值之和为负,称为负环。
伪代码 Start
(初始化)起点距离:0,其他点距离:INF // 不能太大,防止溢出
for n = [1 ~ N) //最多做n-1次,如果做了n-1次之后还有点的距离没更新,那么说明图存在负环。
for e = [1 ~ E]
d[e.v] = min ( d[e.v] , d[e.u] + cost[e] ) //称为松弛操作
for e = [1 ~ E]
if ( d[e.v] > d[e.u] + cost[e] ) return false; //存在负环
return true; //不存在负环
伪代码 End
3、SPFA算法:O(kE) --- 基于Bellman-Ford算法优化,可以处理负边图,并且复杂度较小
用一个先进先出的队列维护,先计算每个点的估计距离,如果发现这个值能再次更新,那么把它重新加入队列,以便检查它相邻的点。
伪代码 Start
(1)(初始化)起点距离:0,其他点距离:INF,新建队列que:推入起点。
(2) 从队首取出top,标记top已出队(负环检查:同时对top出队次数进行检查,如果大于n,说明出现负环,算法结束)。遍历top所连的边e,如果e.to可以更新,那么更新e.to,检查e.to是否在队列中,如果不在加入队列中。
(3) 重复步骤2,直到队列为空。
伪代码 End
二、每两点最短路:Floyd算法 --- 图可以是有向图或者无向图,可以存在负边,但是不能存在负环。
伪代码 Start
(初始化)d[i][i]:0,其他两点间距离:INF //不能太大,防止下文 d[i][k] + d[k][j] 溢出
for k = [0,n)
for i = [0,n)
for j = [0,n)
d[i][j] = min( d[i][j] , d[i][k] + d[k][j] ); //可以加个pre数组,同时记录路径。
伪代码 End
Floyd算法中边权可正可负,只要图中不存在负环都可以得出正确答案。关于Floyd算法的负环判定,见:Floyd求最小环,只要求出的最小环是正的,就不存在负环。
相关文章推荐
- 初学图论-Kahn拓扑排序算法(Kahn's Topological Sort Algorithm)
- 初学图论-Bellman-Ford单源最短路径算法
- 初学图论-DAG单源最短路径算法
- 初学图论-Dijkstra单源最短路径算法
- 初学图论-Dijkstra单源最短路径算法基于优先级队列(Priority Queue)的实现
- 封装好的Folyd建图,C++源码
- LCA模板
- 图论学习笔记之一——Floyd算法
- 【LCA】SPOJ QTREE2
- poj 3249 Test for Job 最长路
- HDU 2544
- Timus 1557 Network Attack DFS+各种各种...
- HDU1289 Tarjan-模板题
- Poj2638 网络流+最短路+二分答案
- Aizu1311 分层图最短路 (...大概)
- HDU 3631 Shortest Path
- 二分图匹配模板
- 最短路径 -- spfa
- Six Degrees of Cowvin Bacon(最短路径floyd算法)
- Edmonds-Karp 最大流 hdu 1532 Drained Ditches