Bellman-Ford算法简述
Dijkstra算法是处理单源最短路径的有效算法,但它局限于边的权值非负的情况,若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的。这时候,就需要使用其他的算法来求解最短路径,Bellman-Ford算法就是其中最常用的一个。该算法由美国数学家理查德•贝尔曼(Richard Bellman, 动态规划的提出者)和小莱斯特•福特(Lester Ford)发明。Bellman-Ford算法的流程如下:
给定图G(V, E)(其中V、E分别为图G的顶点集与边集),源点s,
- 数组Distant[i]记录从源点s到顶点i的路径长度,初始化数组Distant[n]为
, Distant[s]为0; - 以下操作循环执行至多n-1次,n为顶点数:
- 对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;
- 若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;
- 为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) < Distant[v]的边,则图中存在负环路,即是说改图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。
可知,Bellman-Ford算法寻找单源最短路径的时间复杂度为O(V*E).
Bellman-Ford算法C++实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | const int MAXINT = 0xFFFF; //~ 不可达的路径长度上限 struct Node { Node(): w(MAXINT){} int src, //~ 最短路径上的上一个顶点 w; //~ 到该节点的路径长度 }; struct Edge { Edge(){} Edge(int f, int t): from(f), to(t){} int from, to; }; int main(int argc, char **argv) { vector<vector<int> > Adj; int n, // 顶点数 m, //~ 边数 from, to, w, start; //~ 源点 cin>>n; vector<Node> Dist(n); for(int i = 0; i < n; ++i) { Adj.push_back(vector<int>(n, MAXINT)); Adj[i][i] = 0; } cin>>m; vector<Edge> Edges; for(int i = 0; i < m; ++i) { cin>>from>>to>>w; Adj[from][to] = w; Edges.push_back(Edge(from, to)); } cin>>start; //~ 从顶点start开始的最短路径 Dist[start].w = 0; //~ bool flag = true; for( int i = 0; i < n - 1; ++i) { for(int j = 0; j < Edges.size(); ++j) { from = Edges[j].from; to = Edges[j].to; if(Dist[from].w == MAXINT || Adj[from][to] == MAXINT) continue; if(Dist[from].w + Adj[from][to] < Dist[to].w) { Dist[to].w = Dist[from].w + Adj[from][to]; Dist[to].src = from; flag = false; } } if(flag == true) break; else flag = true; } //~ 检测有无负环路 for(int j = 0; j < Edges.size(); ++j) { from = Edges[j].from; to = Edges[j].to; if(Dist[from].w == MAXINT || Adj[from][to] == MAXINT) continue; if(Dist[from].w + Adj[from][to] < Dist[to].w) { cout<<"Negative Length Cycle Detected!"<<endl; return 1; } } //~ 下面代码供测试用 while(cin>>to) { int rp = to; cout<<Dist[to].w<<" "; while(rp != start) //~ 反向输出路径 { cout<<rp<<" <- "; if(Dist[to].w == MAXINT) break; rp = Dist[rp].src; } cout<<start<<endl; } return 0; } |
你好!除了代码,此处没有多少原创之物,皆为本人搜集、整理、总结之记录与心得,欢迎转载分享!转载时请尽量注明出处,将不胜感激。祝你健康、快乐!
你的实现有一定问题:Bellman-Ford本来只需要O(E)的空间,你的实现变成了需要O(n^2)。对于某些情况这是不可接受的(点比较多,比如大于1w,而边比较稀疏,比如在百万或者更少)。