最短路之Bellman Ford SPFA

2021-10-02 16:19:49 字數 2356 閱讀 2032

bellman-ford

時間複雜度o(v*e),用於求帶權圖單源最短路(可含負權,可判斷是否有迴路)

bellman-ford和dijkstra類似,都是以邊的鬆弛操作為基礎,回顧一下鬆弛操作:對於邊(k,j),d[j] = min(d[j],d[k]+w(k,j)),即如果加上這條邊那麼更新起點到j的最短路為二者中最小的那個。但是dijkstra屬於貪心演算法,每次都找剩餘不確定的點中的最短路,但是在處理含負權邊的時候這一方法已不再適用:

假設上圖中1號節點是起點,我們第一次貪心時按dijkstra來說,是確定(1,3)這條邊為1到3的最短路,但是我們發現如果再經過2號節點到達3號節點的路徑更短(因為負權的存在),因此我們就不能再貪心,而是全方面的考慮所有邊

其實bellman-ford還是挺難理解的,建議參考具體的例子,自己畫圖或者參考下面部落格

bellman-ford的演算法思想是:對於所有的邊(u,v,w)來說,每次都對v點進行鬆弛操作更新最短路。那麼經過乙個迴圈就會有的節點最短路被確定而有的節點仍然是估計值,確定值接下來不會再改變,但是估計值接下來會隨著其他節點的確定而確定。例如對於部分節點來說,起點可能不含直接到他的邊,那麼仍然是初始的inf,因此在下面不斷對所有邊鬆弛的過程中,這部分節點會因為其他節點最短路的確定而確定。那麼我們需要執行多少次呢?因為有n個節點,那麼距離起點最遠的節點最多有n-1條邊,因此考慮最壞的情況要對所有邊鬆弛n-1次才能確定最終的結果,於是便得到了下面的**

const

int maxn=

1e5+10;

//點的最大值

const

int maxm=

2e5+10;

//邊的最大值

int d[maxn]

;//起點到每個點的距離

int u[maxm]

,v[maxm]

,w[maxm]

;//省略了結構體寫法

void

bellman_ford

(int s)

}}

除此之外,bellman-ford 演算法還可以檢測出乙個圖是否含有負權迴路。如果進行n-1輪鬆弛操作之後仍然存在"if(dis[v[i]] > dis[u[i]] + w[i]) dis[v[i]] = dis[u[i]] + w[i];"的情況,也就是說在進行n-1輪鬆弛後,仍可以繼續成功鬆弛,那麼此圖必然存在負權迴路。如果乙個圖沒有負權迴路,那麼最短路徑所包含的邊最多為n-1條,即進行n-1輪鬆弛操作後最短路不會再發生變化。如果在第n輪鬆弛時最短路仍然可以發生變化,則這個圖一定有負權迴路

bool bellman_ford

(int s)

return

true

;}

仔細觀察上面**,我們會發現bellman-ford對所有邊進行鬆弛,實際上也相當於對所有邊的to(入)節點進行鬆弛,於是便有了下面的佇列優化spfa

shortest path faster algorithm,用來求含負權邊的最短路徑快速演算法,時間複雜度平均o(k*e),k是小常數,但是可能在最壞的情況下為o(v*e)

spfa實際上是bellman-ford的佇列優化,我們上面提到了每一次遍歷所有邊都會使一些節點的最短路確定,但是這些確定的最短路在接下來仍要判斷,這便是我們可以優化的地方

用陣列d記錄每個結點的最短路徑估計值,而且用鏈式前向星來儲存圖g,因為鏈式前向星是最優的儲存方式。演算法思路為:先設定乙個佇列來儲存待優化的結點,優化時每次取出隊首結點u,並且用u點當前的最短路徑估計值對離開u點所指向的結點v進行鬆弛操作,如果v點的最短路徑估計值有所調整,且v點不在當前的佇列中,就將v點放入隊尾。這樣不斷從佇列中取出結點來進行鬆弛操作,直至佇列空為止,具體為:

如果要判斷是否含有負環,設定乙個記錄節點入隊次數陣列cnt,在while迴圈裡每次入隊時更新該節點入隊次數,如果次數大於n,那麼代表存在負環

const

int maxn=

1e5+10;

const

int maxm=?;

struct node

;node edge[maxm]

;int head[maxn]

,d[maxn]

,cnt[maxn]

;bool vis[maxn]

;int tot,n;

addedge

(int u,

int v,

int w)

bool spfa

(int s)}}

}return

true

;}

最短路之bellman ford演算法

先來說下bellman ford演算法的基本思想。假設在乙個有向圖中有n個點,那麼從源點到任意其他一點的最短路徑數量肯定不超過n 1 假設不含迴路 那樣放鬆一下限制的話,對於任意一條路徑來說,將n 1條邊都嘗試著 鬆弛 一下,那樣的話,肯定就可以將這條路徑變為最短路。對於bellman ford演算...

最短路 Bellman Ford演算法

建立兩個結構體 struct shuzhu 中,u.d存放的是到源節點的當前最短距離,u.f存放的是到節點v的當前最短路徑的前乙個節點 struct node 中,flag 表示的是該節點 的標號,w表示的是邊 u到v的權重。核心 鬆弛距離 if v.d u.d w 在 中就是 if a q fla...

bellman ford演算法 最短路

重要應用 在負權的圖的單源最短路問題 bellman ford 演算法和 dijkstra 演算法都是可以解決單源最短路徑的演算法,乙個實現的很好的 dijkstra 演算法比 bellman ford 演算法的執行時間要低,但dijkstra演算法無法解決存在負權環的圖的單源最短路問題 因為dij...