[算法导论读书笔记]Bellman-Ford算法(单源最短路径)
来源:互联网 发布:国际编程证书 编辑:程序博客网 时间:2024/06/11 23:48
Bellman-Ford算法与另一个非常著名的Dijkstra算法一样,用于求解单源点最短路径问题。Bellman-ford算法除了可求解边权均非负的问题外,还可以解决存在负权边的问题(意义是什么,好好思考),而Dijkstra算法只能处理边权非负的问题,因此 Bellman-Ford算法的适用面要广泛一些。但是,原始的Bellman-Ford算法时间复杂度为 O(VE),比Dijkstra算法的时间复杂度高,所以常常被众多的大学算法教科书所忽略,就连经典的《算法导论》也只介绍了基本的Bellman-Ford算法,在国内常见的基本信息学奥赛教材中也均未提及,因此该算法的知名度与被掌握度都不如Dijkstra算法。事实上,有多种形式的Bellman-Ford算法的优化实现。这些优化实现在时间效率上得到相当提升,例如近一两年被热捧的SPFA(Shortest-Path Faster Algoithm 更快的最短路径算法)算法的时间效率甚至由于Dijkstra算法,因此成为信息学奥赛选手经常讨论的话题。然而,限于资料匮乏,有关Bellman-Ford算法的诸多问题常常困扰奥赛选手。如:该算法值得掌握么?怎样用编程语言具体实现?有哪些优化?与SPFA算法有关系么?本文试图对Bellman-Ford算法做一个比较全面的介绍。给出几种实现程序,从理论和实测两方面分析他们的时间复杂度,供大家在备战省选和后续的noi时参考。
Bellman-Ford算法思想
Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。对于给定的带权(有向或无向)图 G=(V,E),其源点为s,加权函数 w是 边集 E 的映射。对图G运行Bellman-Ford算法的结果是一个布尔值,表明图中是否存在着一个从源点s可达的负权回路。若不存在这样的回路,算法将给出从源点s到 图G的任意顶点v的最短路径d[v]。
Bellman-Ford算法流程分为三个阶段:
(1) 初始化:将除源点外的所有顶点的最短距离估计值 d[v] ←+∞, d[s] ←0;
(2) 迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次)
(3) 检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 d[v]中。
算法描述如下:
Bellman-Ford(G,w,s) :boolean //图G ,边集 函数 w ,s为源点
1 for each vertex v ∈ V(G) do //初始化 1阶段
2 d[v] ←+∞
3 d[s] ←0; //1阶段结束
4 for i=1 to |v|-1 do //2阶段开始,双重循环。
5 for each edge(u,v) ∈E(G) do //边集数组要用到,穷举每条边。
6 If d[v]> d[u]+ w(u,v) then //松弛判断
7 d[v]=d[u]+w(u,v) //松弛操作 2阶段结束
8 for each edge(u,v) ∈E(G) do
9 If d[v]> d[u]+ w(u,v) then
10 Exit false
11 Exit true
代码示例:
#include <iostream>#include <stdio.h>using namespace std;#define MAX 100000#define N 1010int nNode, nEdge, original;typedef struct Edge{int u, v;int cost;}Edge;Edge edge[N];int d[N], pre[N];void Relax(int u, int v, int w){if(d[v] > d[u] + w ){d[v] = d[u] + w;pre[v] = u;}}void Initialize_Single_source(){for( int i = 1; i <= nNode; i++){d[i] = MAX;pre[i] = 0;}d[original] = 0;}bool Bellman_Ford(){Initialize_Single_source();for( int i = 1; i < nNode; i++ ){for( int j = 1; j <= nEdge; j++){Relax(edge[j].u, edge[j].v, edge[j].cost);}}for( int j = 1; j <= nEdge; j++){if( d[edge[j].u] > d[edge[j].v] + edge[j].cost){return false;}return true;}}void Print_Path(int root){ if(0 != root){Print_Path(pre[root]);printf("-->%d", root);}}int main(int argc, char* argv[]){scanf("%d%d%d", &nNode, &nEdge, &original);for( int i = 1; i <= nEdge; i++ ){scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);}if (Bellman_Ford()){for( int i = 1; i <= nNode; i++){printf("\nnode%d: %d(km)\tPath:",i, d[i]);Print_Path(i);}printf("\n");}else{printf("Have negative circle\n");}return 0;}测试结果:
参考资料:
http://www.cppblog.com/infinity/archive/2011/10/20/66621.html
http://blog.csdn.net/niushuai666/article/details/6791765
- [算法导论读书笔记]Bellman-Ford算法(单源最短路径)
- 算法导论 ch24 单源最短路径 Bellman-Ford
- 算法导论 单源最短路径 Bellman-Ford
- 【算法导论】单源最短路径之Bellman-Ford算法
- 单源最短路径Bellman-Ford算法
- 单源最短路径 : Bellman-Ford 算法
- 单源最短路径-Bellman-Ford算法
- 单源最短路径--Bellman-Ford算法
- 单源最短路径-Bellman-Ford算法
- 单源最短路径-Bellman-ford算法
- Bellman-Ford 单源最短路径算法
- 算法导论-最短路径-Dijkstra算法+Bellman-Ford 算法
- 单源最短路径算法之Bellman-Ford算法
- 图—单源最短路径算法(一)Bellman-Ford算法
- 图--单源最短路径 -Bellman Ford 算法(可以存在负权边的情况和负权回路)算法导论p362
- 算法导论-第24章- 单源最短路径 - 24.1 Bellman-Ford 算法
- Bellman-Ford算法 单源最短路径(o(nm))
- Bellman-Ford 算法实现单源最短路径
- 移植Busybox与构建根文件系统
- 深入浅出VMware的组网模式
- 小白鼠算法
- 我不该纠结与那些我无法控制的事情~!
- 第6周任务3
- [算法导论读书笔记]Bellman-Ford算法(单源最短路径)
- 介绍如何使用 POSIX 库在多线程环境中设计并发数据结构
- MFC类图
- 概率题
- MFC疑难注解:CAsyncSocket及CSocket
- asp.net用datalist进行分页
- sipdroid在ubuntu下的编译
- 篇头语
- 第六周实验报告(任务三)【平面坐标点类】