Dijkstra算法是处理单源最短路径的有效算法,但它局限于边的权值非负的情况,若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的。这时候,就需要使用其他的算法来求解最短路径,Bellman-Ford算法就是其中最常用的一个。
1、Bellman-Ford算法的流程如下:
①数组dist[i]记录从源点s到顶点i的路径长度,初始化数组dist[n]为INF, dist[s]为0;
②以下操作循环执行至多n-1次,n为顶点数:
对于每一条边e(u, v),如果dist[u] + w(u, v) < dist[v],则另dist[v] = dist[u]+w(u, v)。w(u, v)为边e(u,v)的 权值;
③若上述操作没有对dist进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;
④为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在dist[u] + w(u, v) < dist[v]的边,则图中存在负环路,即是说该图无法求出单源最短路径。否则数组dist[n]中记录的就是源点s到各顶点的最短路径长度。
2、参考代码
/** 该代码修改自《挑战程序设计》第二版 */ #include <iostream> #include <string.h> #include <stack> #define INF 1000000000 #define MAX_E 99 #define MAX_V 100 using namespace std; struct edge{ int from,to,cost;//边的起点,终点,权值 }; edge es[MAX_E]; int d[MAX_V];//源点到顶点的最短距离 int path[MAX_V];//存最短路径 int V,E;//顶点数,边数 int s;//源点 void BellmanFord(int s); bool find_negative_loop();//判断是否有负环 void Print(); int main() { cout << "请输入图的顶点数,边数,源点:"; cin >>V>>E>>s; cout << "请输入" <<E<< "条边的起点、终点以及权值: "; for (int i = 0; i <E; i++) cin >>es[i].from>> es[i].to >> es[i].cost; if(!find_negative_loop()){ BellmanFord(s); Print(); }else{ cout<<"有负环"<<endl; } return 0; } void BellmanFord(int s){ for(int i=0;i<V;i++){ d[i]=INF; } d[s]=0; while(true){//最多循环V-1次 bool update=false; for(int i=0;i<E;i++){ edge e=es[i]; if(d[e.from]!=INF&&d[e.to]>d[e.from]+e.cost){ d[e.to]=d[e.from]+e.cost; path[e.to]=e.from; update=true; } } if(!update)//如果没有边的距离更新说明已经找完了 break; } } bool find_negative_loop(){ memset(d,0,sizeof(d)); for(int i=0;i<V;i++){ for(int j=0;j<E;j++){ edge e=es[j]; if(d[e.to]>d[e.from]+e.cost){ d[e.to]=d[e.from]+e.cost; if(i== V-1)return true;//如果其在第V次仍然更新则说明其有负环 ///因为最短路径不可能经过同一个点两次,所以最多循环V-1次 ///但如果有负环会无限循环下去,自己可以举个栗子试一下 } } } return false; } void Print() { for (int i = 0; i < V; i++) { if (i != s) { int p = i; stack<int> st; cout << "顶点 " << s << " 到顶点 " << p << " 的最短路径是: "; while (s != p) //路径顺序是逆向的,所以先保存到栈 { st.push(p); p = path[p]; } cout << s; while (!st.empty()) //依次从栈中取出的才是正序路径 { cout << "--" << st.top(); st.pop(); } cout << " 最短路径长度是:" << d[i] << endl; } } }