最短路徑分析的算法

Floyd-Warshall(弗洛伊德算法)

弗洛伊德算法的主要思想是通過第三點來縮短兩點間的路徑,例如頂點a和頂點b之間的路徑爲dis[a][b],如果想使a,b之間的路徑縮短,只有引入第三點k,並通過k點來中轉,即a->k->b,纔可能縮短a,b之間的路徑,那麼這個k點是哪個點呢,其實並不唯一,k點也有可能有多個,但可以確定的是,在經過k點中轉後,所得到的dis[a][k]+dis[k][b]一定小於中轉前的dis[a][b],所以就可以總結爲從a點到b點只經過前k個點的最短路徑,是不是感覺這句話有點熟悉呢[滑稽],沒錯,這就是動態規劃的思想。

Dijkstra(迪傑斯特拉)算法

迪傑斯特拉算法是解決單個點到其餘各點最短路徑的算法,其主要思想爲通過其他邊來鬆弛單個點到其餘各點的路程。這裏我們還需要定義一個dis數組,表示該點到其餘各點的未確定最短距離。然後從dis數組中選取一個最小值(離始點最近的點),將它的距離確定爲最短,這裏是因爲每條邊都是正數,那麼肯定不可能通過第三個點來使得此時距始點最短的距離更短了,因爲始點到其他點的距離都比到這個點的距離要大。

然後我們就可以通過這個點的邊來對始點到其他點的邊進行“鬆弛”,比如設始點爲1號點,剛剛確定爲最短路徑的點爲2號點,然後此時的dis[3]=10,dis[2]=1,e[2][3]=4(始點爲2,終點爲3的邊),這時我們就可以通過e[2][3]這條邊來對dis[3]進行鬆弛,因爲dis[3]>dis[2]+e[2][3],所以此時的dis[3]應更新爲5。

這便是迪傑斯特拉算法的主要思想:通過其他邊來鬆弛單個點到其餘各點的路程。

這樣我們就可以總結出算法的基本步驟了:每次找到離始點最近的一個頂點,通過這個點的邊來對始點到其餘各點的邊進行鬆弛,最終得到始點到其餘各點的最短路徑。

Bellman-Ford(貝爾曼-福特)算法——解決負權邊

在以上介紹的兩種算法中雖然很好的解決了最短路徑問題,但多多少少都有一些缺陷,比如無法解決帶有負權迴路的圖。現在我們介紹的這種Bellman-Ford算法就能夠解決負權邊問題啦O(∩_∩)O~

Bellman-Ford算法其實操作方法與Dijkstra算法如出一轍,只不過它沒有進行最短路徑的猜測,而是對每一條邊都進行了n-1次鬆弛,這樣就確保了每一條邊最後都能到達它的最短路徑。

SPFA(Bellman-Ford算法的隊列優化)

在剛剛的算法中我們提到,對每一條邊都進行n-1次的鬆弛,可能會進行很多不必要的操作,浪費掉很多時間,順便說一下,不進行優化的Bellman-Ford算法的時間複雜度爲O(nm),而經過隊列優化的Bellman-Ford算法的時間複雜度最壞情況下也是O(nm),但是一般是達不到的。

那麼我們應該如何利用隊列進行優化呢?我們可以將始點u放入隊列,然後對u的所有出邊進行鬆弛。例如有一條u->v的邊,如果通過u->v這條邊使得始點到頂點v的路程變短(dis[u]+e[u][v]<dis[v]),且頂點v不在隊列中,就將點v放入隊尾,點u鬆弛完畢後,就將點u出隊,繼續進行下一點的出邊鬆弛,直到隊列爲空。

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