單源最短路問題是固定一個起點,求它到其他所有點的最短路的問題。
算法:
設 d[i] 表示 起點 s 離點 i 的最短距離。
【1.初始化】 固定起點s,對所有的點 , 如果 i = s , d[i] 置為 0 ;如果 i != s , d[i] 置為 INF,執行 2。
【2.更新】 update = false。 用所有的邊更新所有的點離源點的距離,update = true。
如果更新過update = true,重復執行2 ; 如果沒有更新過update = false, 執行3。
【3.輸出】 打印 d 數組中所求的結果。
代碼:
#include <bits\stdc++.h> using namespace std; #define INF 2147483647 #define MAX_V 1000 #define MAX_E 2000 // 單源最短路徑1(Bellman-Ford算法) struct edge{ int from,to,cost; }; edge es[MAX_E]; //所有的邊 int d[MAX_V]; //d[i]表示源點到i點的最短距離 int V,E; //V是頂點數,E是邊數 //求解從s離所有點的距離 void shortest_path(int s){ for(int i = 0;i < V; i++) d[i] = INF; d[s] = 0; //用可到達的點和從這個點出發的邊更新這條邊到達的點與源點的距離。 //如果無點可更新,則跳出 while(true){ 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; update = true; } } if(!update) break; } } int main(){ }
負圈:負圈又稱負環,就是說一個全部由負權的邊組成的環,這樣的話不存在最短路,因為每在環中轉一圈路徑總長就會變小。
Bellman-Ford算法求最短路徑不會經過同一個點兩次。如果不存在負圈的話最多會更新 V-1 次,即每次只更新出一個點(想象一下線性存儲的情況)。
如果有負圈的話會無限更新下去。
所以判斷負圈是否存在只用判斷是否更新了大於V-1次即可。
代碼:
#include <bits\stdc++.h> using namespace std; #define INF 2147483647 #define MAX_V 1000 #define MAX_E 2000 // 單源最短路徑1(Bellman-Ford算法) struct edge{ int from,to,cost; }; edge es[MAX_E]; //所有的邊 int d[MAX_V]; //d[i]表示源點到i點的最短距離 int V,E; //V是頂點數,E是邊數 //判斷是否存在負圈 bool find_negative_loop(){ memset(d,0,sizeof(d)); for(int i = 1;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; //如果更新了V次說明存在負圈 if(i == V) return true; } } } return false; } int main(){ }