Bellman Ford 演算法解決最短路徑問題

2022-08-31 03:12:09 字數 3762 閱讀 6792

bellman - ford 演算法:

一:基本演算法

bellman - ford 演算法可以處理路徑權值為負數時的單源最短路徑問題.設想可以從圖中找到乙個環路且這個環路中所有路徑的權值之和為負.那麼通過這個環路,環路中任意兩點的最短路徑就可以無窮小下去.如果不處理這個負環路,程式就會永遠執行下去.bellman -ford 演算法具有分辨這種負環路的能力.

bellman - ford演算法基於動態規劃,反覆用已有的邊來更新最短距離,bellman - ford演算法的核心就是鬆弛.對於點 v 和 u,如果 dist[u] 和 dist[v] 不滿足 dist[v] <= dist[u] + map[u][v],那麼dist[v] 就應該被更新為 dist[u] + map[u][v].反覆地利用上式對每條邊進行鬆弛,從而更新 dist 陣列,如果沒有負權迴路的話,應當會在 n - 1 次鬆弛之後結束演算法.原因在於考慮對每條邊進行 1 次鬆弛的時候,得到的實際上是至多經過 0 個點的最短路徑(初始化每個點到源點的距離為無窮,這裡的經過 0 個點意思為路徑僅由源點和終點組成),對每條邊進行兩次鬆弛的時候得到的至多是經過 1 個點的最短路徑,如果沒有負權迴路,那麼任意兩點的最短路徑至多經過 n - 2 個點(不包含源點和終點這兩個點),因此經過 n - 1 次鬆弛操作後應當可以得到最短路徑.如果有負權迴路,那麼第 n 次鬆弛操作仍然會成功(即第 n 次鬆弛仍然存在一條邊可以對其進行鬆弛操作),但是不存在負權迴路的圖應該在第 n - 1 次鬆弛之後,已經不存在可以鬆弛的邊了,所以bellman -ford演算法就利用了這個性質以達到判定負環的目的.

二:偽**

在以下說明中: s 為源, map 記錄圖的資訊,map[u][v] 為點 u 到點 v 的邊的長度,如果 u 和 v 之間不存在邊那麼 map[u][v] = inf, 結果儲存在 dist陣列裡:

(1):初始化,所有點 i 賦初值 dist[i] = inf, 出發點為 s, dist[s] = 0.

(2):對於每條邊,如果 dist[u] != inf, 且 dist[v] > dist[u] + map[u][v],則 dist[v] = map[u] + map[u][v].

(3):迴圈步驟(2)  n - 1 次或直到某次迴圈中不再更新,進入步驟(4).

(4):對於每條邊, 如果 dist[u] != inf, 且dist[v] > dist[u] + map[u][v],則存在負權迴路.

for i = 0 to n - 1

}}

三:以圖為例初始化圖, dist[i]代表當前點 i 距離源點 「5」 的最短距離, 圖中存在兩調負權邊,但不存在負環,紅色的點代表源點,紅色的邊代表正在鬆弛的邊,綠色的點代表正在鬆弛的邊的起點,藍色的點代表正在鬆弛的邊的終點:

第一次迴圈:

(從點 「1」 ~ 到點 "6" 選擇 dist[i] != inf 的點):

第乙個選中的點為 「5」,則對從點 「5」 出發的所有邊進行鬆弛操作:

由於之後沒有了可以選擇的點了,所以第一次迴圈結束.

第二次迴圈:

(從點 「1」 ~ 到點 "6" 選擇 dist[i] != inf 的點):

第乙個選中的點為 「3」,則對從點 「3」 出發的所有邊進行鬆弛操作:

第二個選中的點為點 「4」,對所有從點 「4」 出發的所有邊進行鬆弛:

第三個選中的點為點 「5」,這裡很顯然可以看出,邊 和邊 不用進行鬆弛.

第四個選中的點為點 「6」,然後依次嘗試對邊 進行鬆弛:

到這裡,第二次迴圈結束.

第三次迴圈:

(從點 「1」 ~ 到點 "6" 選擇 dist[i] != inf 的點):

第乙個選中的點為 「1」,則對從點 「1」 出發的所有邊進行鬆弛操作:

第二個選中的點為點 「2」,則對所有從點 「2」出發的所有嘗試鬆弛操作:

第三個選中的點為點 「3」,嘗試對所有從 點「3」出發的邊進行鬆弛,可以很清楚看到邊 無法鬆弛,dist[4] <= dsit[3] + map[3][4]成立.

第四個選中的點為點 「4」,嘗試對所有從 點「4」出發的邊進行鬆弛:

第五個選中的點為點 「5」,嘗試對所有從點 「5」 出發的邊進行鬆弛,也可以很清楚看到,邊 和邊 不用進行鬆弛.

第六個選中的點為點 「6」,嘗試對所有從點 「6」 出發的邊進行鬆弛:

至此第三次已經結束.

第四次迴圈:

(從點 「1」 ~ 到點 "6" 選擇 dist[i] != inf 的點):

選擇點 「1」.......

選擇點 「2」.......

選擇點 「3」.......

選擇點 「4」.......

選擇點 「5」.......

選擇點 「6」.......

執行完第四次迴圈,會發現所有的邊都未再次進行鬆弛,事實上演算法至此已經求出源點到其他各頂點的最短路徑,此時演算法應該結束.

最後的最短路經為:

四:**

使用鏈式前向星存圖的資訊:

1

const

int inf = 1000;2

const

int maxn =10000;3

const

int maxe =100000;4

int dist[maxn + 3];//

dist[i]表示點 i 到源點的最短距離56

int head[maxn + 3];//

鏈式前向星用於存圖

7struct node ;

8 node edge[maxe + 3];9

10bool bellmanford(int n, int s) 20}

21}22}

23for(int j = 1; j <= n; j++) 27}

28return

true

;29 }

參考《圖論及應用》和網上部分資料.

Bellman Ford演算法 解決負權邊

dijkstra演算法雖然好,但是它不能解決帶有負權邊 邊的權值為負數 的圖。接下來學習一種無論在思想上還是在 實現上都可以稱為完美的最短路徑演算法 bellman ford演算法。bellman ford演算法非常簡單,核心 四行,可以完美的解決帶有負權邊的圖。for k 1 k n 1 k 外迴...

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...