dijkstra演算法雖然好,但是它不能解決帶有負權邊(邊的權值為負數)的圖。
接下來學習一種無論在思想上還是在**實現上都可以稱為完美的最短路徑演算法:bellman-ford演算法。
bellman-ford演算法非常簡單,核心**四行,可以完美的解決帶有負權邊的圖。
for(k=1;k<=n-1;k++) //外迴圈迴圈n-1次,n為頂點個數在乙個含有n個頂點的圖中,任意兩點之間的最短路徑最多包含n-1條邊,最短路徑中不可能包含迴路。for(i=1;i<=m;i++)//內迴圈迴圈m次,m為邊的個數,即列舉每一條邊
if(dis[v[i]]>dis[u[i]]+w[i])//嘗試對每一條邊進行鬆弛,與dijkstra演算法相同
dis[v[i]]=dis[u[i]]+w[i];
因為最短路徑是乙個不包含迴路的簡單路徑,迴路分為正權迴路(迴路權值之和為正)和負權迴路(迴路權值之和為負)。如果最短路徑中包含正權迴路,那麼去掉這個迴路,一定可以得到更短的路徑;如果最短路徑中包含負權迴路,那麼肯定沒有最短路徑,因為每多走一次負權迴路就可以得到更短的路徑. 因此最短路徑肯定是乙個不包含迴路的最短路徑,即最多包含n-1條邊。
bellman-ford演算法的主要思想:
首先dis陣列初始化頂點u到其餘各個頂點的距離為∞,dis[u] = 0。
然後每輪對輸入的所有邊進行鬆弛,更新dis陣列,至多需要進行n-1次就可以求出頂點u到其餘各頂點的最短路徑(
因為任意兩點之間的最短路徑最多包含n-1條邊,所以只需要n-1輪就行)。
一句話概括bellman-ford演算法就是:對所有邊進行n-1次「鬆弛」操作。
此外,bellman-ford演算法可以檢測乙個圖是否有負權迴路。如果已經進行了n-1輪鬆弛之後,仍然存在
if(dis[v[i]]>dis[u[i]]+w[i])的情況,也就是說在進行n-1輪之後,仍然可以繼續成功鬆弛,那麼這個圖一定存在負權迴路。dis[v[i]]=dis[u[i]]+w[i];
關鍵**如下:
//顯然,演算法複雜度為o(nm),比dijkstra演算法還高,當然可以進行優化。bellman-ford演算法核心語句
for(k=1;k<=n-1;k++) //
外迴圈迴圈n-1次,n為頂點個數
for(i=1;i<=m;i++)//
內迴圈迴圈m次,m為邊的個數,即列舉每一條邊
if(dis[v[i]]>dis[u[i]]+w[i])//
嘗試對每一條邊進行鬆弛,與dijkstra演算法相同
dis[v[i]]=dis[u[i]]+w[i];
//檢測負權迴路
flag=0
;for(i=1;i<=m;i++)
if(dis[v[i]]>dis[u[i]]+w[i])
flag=1
;if(flag==1
) printf(
"此圖有負權迴路
");
在實際操作中,bellman-ford演算法經常會在沒有達到n-1輪鬆弛前就已經計算出最短路,上面已經說過,n-1其實是最大輪迴次數。
因此可以新增乙個變數check用來標記陣列dis在本輪鬆弛中是否發生了變化,若沒有變化,則提前跳出迴圈。
完整**如下:
#include #define inf 999999intmain()
//初始化dis陣列,這裡是1號頂點到其餘頂點的初始路程
for (i = 1; i <= n; ++i)
dis[
1] = 0
;
//bellman-ford演算法核心**
for (j = 1; j <= n-1; ++j) //
最多迴圈n-1輪
}//鬆弛完畢後檢測陣列dis是否有更新
if (check==0
)
}//檢測負權迴路
for (i = 1; i <= m; ++i) //
n-1次之後最短路徑還會發生變化則含有負權迴路
Bellman Ford 演算法解決最短路徑問題
bellman ford 演算法 一 基本演算法 bellman ford 演算法可以處理路徑權值為負數時的單源最短路徑問題.設想可以從圖中找到乙個環路且這個環路中所有路徑的權值之和為負.那麼通過這個環路,環路中任意兩點的最短路徑就可以無窮小下去.如果不處理這個負環路,程式就會永遠執行下去.bell...
Bellman Ford演算法,SPFA演算法
bellman ford 演算法能在更普遍的情況下 存在負權邊 解決單源點最短路徑問題。對於給定的帶權 有向或無向 圖g v,e 其源點為 s,加權函式w是 邊集e 的對映。對圖g執行 bellman ford 演算法的結果是乙個布林值,表明圖中是否存在著乙個從源點s 可達的負權迴路。若不存在這樣的...
Bellman ford 演算法詳解
昨天說的dijkstra固然很好用,但是卻解決不了負權邊,想要解決這個問題,就要用到bellman ford.我個人認為bellman ford比dijkstra要好理解一些,還是先上資料 有向圖 5 712 8135 23 6 5 4 324 735 2 45 3 在講述開,先設幾個陣列 orig...