Bellman-Ford算法 單源最短路問題

定義:

單源最短路問題是固定一個起點,求它到其他所有點的最短路的問題。終點也固定的問題叫做兩點之間最短路問題。但是因爲解決單源最短路問題的複雜度也是一樣的, 因此通常當作單源最短路問題來求解。

分析:

記從起點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,那麼可以檢查出所有的負圈。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章