Bellman-Ford 算法
阿新 • • 發佈:2017-08-06
局限 sizeof 記錄 最短 max 正序 ack std man
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> #defineINF 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<< "條邊的起點、終點以及權值:\n"; 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; } } }
Bellman-Ford 算法