dijkstra算法爲什麼不能計算負權重?

  這幾天在看迪傑斯特拉算法(dijkstra算法)的時候,瞭解到這個算法不能夠計算負權重,這讓我很納悶???爲什麼呢???下面我按照我理解的解釋一番,若有錯誤希望閱讀者能夠評論指出,不勝感激。
在這裏插入圖片描述
我們看上圖,求A到其他節點的最短路徑:
  首先得出A -> B = 1,A -> C = 0,A -> D = 99,然後將A被標記訪問過。
接着找B到其他節點的距離,看看能不能更新上述節點間距離或者找到其他新節點。找到一個B -> C = 1,A -> B + B -> C = 2 > A -> C = 0,所以不予更新A -> C的節點距離,此時將B被標記訪問過。
  再接着找C到其他節點的距離,發現C那個節點也到不了,也沒有發現新節點,此時將C被標記訪問過。
  再接着重點就來了,D -> B = -300,保證了A -> D + D -> B = -201 < A -> B = 1,則更新A -> B = -201,此時將D被標記訪問過。
  但是,我們明顯可以看出,A -> D + D -> B + B -> C = -200 < A -> C = 0,也就是說應該更新A -> C = -200,但是再進行D的操作前,A,B,C三個節點已經被標記訪問過。此時無法訪問了啊。
  這就是它無法計算負權重的原因,但並不是這個算法在所有包含負權重的圖都無法正確計算。然後既然dijkstra算法計算負權重是有問題的,有什麼算法來解決嘛?怎麼解決的呢?

首先有一個解決算法——Bellman-ford算法,我們可以看下面這篇博客瞭解它的處理步驟。
Bellman-ford算法詳解——負權環分析
  按照Bellman-ford算法的步驟,我們先初始化節點A到本身和其他節點的距離爲dis[0, inf,inf,inf],然後再保存所有邊的權值以及邊的兩個節點(A -> B = 1,A -> C = 0,A -> D = 99,D -> B = -300,B -> C = 1),接着雙重循環(一會解釋爲什麼要雙循環)。
  1.第一條邊A -> B = 1,判斷dis[B] > dis[A] + A -> B => inf > 0 + 1 => true , 則更新dis[0, 1,inf,inf];
  2.第二條邊A -> C = 0,判斷dis[C] > dis[A] + A -> C => inf > 0 + 0 => true ,則更新dis[0, 1,0,inf];
  3.第三條邊A -> D = 99,判斷dis[D] > dis[A] + A -> D => inf > 0 + 99 => true ,則更新dis[0, 1,0,99];
  4.第四條邊D -> B = -300,判斷dis[B] > dis[D] + D -> B => 1 > 99 + (-300) => true ,則更新dis[0, -201,0,99];
  5.第四條邊B -> C = -300,判斷dis[C] > dis[B] + B -> C => 0 > -201 + 1 => true ,則更新dis[0, -201,-200,99];
  此時按照人工判斷已經是最短路徑了,不需要最外層的循環了,但是爲什麼還要最外層循環呢?最裏層的循環我們已經知道了,是遍歷邊!!!,最外層的循環其實也是遍歷邊,爲什麼?你想一想經過最裏層的遍歷邊後,邊的權值路徑是不是都更新了?萬一其他邊還可以基於上次更新的邊再次更新呢?最外層的循環就是爲了處理這個情況。
  外層循環只節點數-1次,因爲最短路徑就算包括所有頂點(這些頂點肯定是不重複的),那麼邊最多也就有節點數–1個。而外層循環在算法中的含義就是,每執行一次外層循環,那麼便最短路徑的邊的個數加1,所以外層循環只節點數-1次。
  內層循環待表的是總邊數。
這種算法有什麼缺點或者優化嗎?
  缺點:不可以出現負權環。
  這是爲什麼呢?舉個例子
在這裏插入圖片描述
  1.第一次遍歷後,點C的值變爲5,點B的值變爲8,這時,注意權重爲-10的邊,這條邊的存在,導致點A的值變爲-2。(8+-10=-2)。
  2.第二次遍歷後,點C的值變爲3,點B變爲6,點A變爲-4。
  …
  正是因爲有一條負邊在迴路中,導致每次遍歷後,各個點的值不斷變小。而且這是無限循環的。
  優化:正如我們第一個例子,在循環一次就已經確定了最短路徑,但是按照原算法還要繼續進行循環下去,這是無用功呢,於是可以在循環中設置判定,在某次循環不再進行鬆弛時,直接退出循環,進行負權環判定。
如果文中我的理解有偏差或者錯誤,請閱讀者評論指出,不勝感激。

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