定義:
單源最短路問題是固定一個起點,求它到其他所有點的最短路的問題。終點也固定的問題叫做兩點之間最短路問題。但是因爲解決單源最短路問題的複雜度也是一樣的, 因此通常當作單源最短路問題來求解。
分析:
記從起點s出發到頂點的最短距離爲dp[i]。則下述等式成立。
dp[i]=min {dp[i]+(從j到i的邊的權值)|e=(j,)∈E} :
如果給定的圖是一個DAG(有向無環圖), 就可以按拓撲序給頂點編號,並利用用這條遞推關係式計算出dp。但是,如果圖中有圈,就無法依賴這樣的順序進行計算。在這種情況下,記當前到頂點的最短路長度爲dp[i],並設初值a[s]=0, dp[i]=INF (足夠大的常數),再不斷使用這條遞推關係式更新dp的值,就可以算出新的dp。只要圖中不存在負圈,這樣的更新操作就是有限的。結束之後的dp就是所求的最短距離了。
實現:
#include<iostream>
#include<vector>
using namespace std;
int n,m;//n個頂點m條邊
struct edge {
int from,to,value;
};
vector<struct edge>mp;
const int INF=1e9;
vector<int>dp(1003,INF);
void Bellman_Ford(int s) {
dp[s]=0;
while(1) {
int update=false;
for(int i=0; i<mp.size(); ++i) {
if(dp[mp[i].from]!=INF&&dp[mp[i].to]>dp[mp[i].from]+mp[i].value) {//更新所有頂點的最小權值
dp[mp[i].to]=dp[mp[i].from]+mp[i].value;
update=true;
}
}
if(!update)//若圖上的所有頂點都不再更新時則代表單源最短路以尋找完畢
break;
}
}
int main() {
cin>>n>>m;
for(int i=0; i<m; ++i) {
int a,b,c;
cin>>a>>b>>c;
mp.push_back({a,b,c});//無向圖寫法
mp.push_back({b,a,c});
}
int s;
cin>>s;
Bellman_Ford(s);
cout<<dp[6];
}
這個算法叫做Bellman-Ford算法。如果在圖中不存在從s可達的的負圈,那麼最短路不會經過同一個頂點兩次(也就是說,最多通過IV-1條邊), while(true)的循環最多執行|V-1|次, 因此,複雜度是O(n*E)。反之,如果存在從s可達的負圈,那麼在第M次循環中也會更新dp的值,因此也可以用這個性質來檢查負圈。如果一開始對所 有的頂點i,都把dp[j]初始化爲0,那麼可以檢查出所有的負圈。