SPFA 演算法詳解

2022-07-17 06:00:15 字數 3393 閱讀 6435

適用範圍:給定的圖存在負權邊,這時類似dijkstra等演算法便沒有了用武之地,而bellman-ford演算法的複雜度又過高,spfa演算法便派上用場了。 我們約定有向加權圖g不存在負權迴路,即最短路徑一定存在。當然,我們可以在執行該演算法前做一次拓撲排序,以判斷是否存在負權迴路,但這不是我們討論的重點。

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

期望的時間複雜度o(ke), 其中k為所有頂點進隊的平均次數,可以證明k一般小於等於2。

實現方法:

建立乙個佇列,初始時佇列裡只有起始點,再建立乙個**記錄起始點到所有點的最短路徑(該**的初始值要賦為極大值,該點到他本身的路徑賦為0)。然後執行鬆弛操作,用佇列裡有的點作為起始點去重新整理到所有點的最短路,如果重新整理成功且被重新整理點不在佇列中則把該點加入到佇列最後。重複執行直到隊列為空。

判斷有無負環:

如果某個點進入佇列的次數超過n次則存在負環(spfa無法處理帶負環的圖)

首先建立起始點a到其餘各點的

最短路徑**

首先源點a入隊,當佇列非空時:

1、隊首元素(a)出隊,對以a為起始點的所有邊的終點依次進行鬆弛操作(此處有b,c,d三個點),此時路徑**狀態為:

在鬆弛時三個點的最短路徑估值變小了,而這些點佇列中都沒有出現,這些點

需要入隊,此時,佇列中新入隊了三個結點b,c,d

隊首元素b點出隊,對以b為起始點的所有邊的終點依次進行鬆弛操作(此處只有e點),此時路徑**狀態為:

在最短路徑表中,e的最短路徑估值也變小了,e在佇列中不存在,因此e也要

入隊,此時佇列中的元素為c,d,e

隊首元素c點出隊,對以c為起始點的所有邊的終點依次進行鬆弛操作(此處有e,f兩個點),此時路徑**狀態為:

在最短路徑表中,e,f的最短路徑估值變小了,e在佇列中存在,f不存在。因此

e不用入隊了,f要入隊,此時佇列中的元素為d,e,f

隊首元素d點出隊,對以d為起始點的所有邊的終點依次進行鬆弛操作(此處只有g這個點),此時路徑**狀態為:

在最短路徑表中,g的最短路徑估值沒有變小(鬆弛不成功),沒有新結點入隊,佇列中元素為f,g

隊首元素f點出隊,對以f為起始點的所有邊的終點依次進行鬆弛操作(此處有d,e,g三個點),此時路徑**狀態為:

在最短路徑表中,e,g的最短路徑估值又變小,佇列中無e點,e入隊,佇列中存在g這個點,g不用入隊,此時佇列中元素為g,e

隊首元素g點出隊,對以g為起始點的所有邊的終點依次進行鬆弛操作(此處只有b點),此時路徑**狀態為:

在最短路徑表中,b的最短路徑估值又變小,佇列中無b點,b入隊,此時佇列中元素為e,b

隊首元素e點出隊,對以e為起始點的所有邊的終點依次進行鬆弛操作(此處只有g這個點),此時路徑**狀態為:

在最短路徑表中,g的最短路徑估值沒變化(鬆弛不成功),此時佇列中元素為b

隊首元素b點出隊,對以b為起始點的所有邊的終點依次進行鬆弛操作(此處只有e這個點),此時路徑**狀態為:

在最短路徑表中,e的最短路徑估值沒變化(鬆弛不成功),此時隊列為空了

最終a到g的最短路徑為14

(⊙v⊙)嗯! **:

1

#include

2#include

3#include

4using

namespace

std;56

const

int maxn=1001;7

const

int inf=999999;8

9int map[maxn][maxn];//

記錄權值

10int path[maxn];//

記錄路徑

11int dis[maxn];//

記錄最短值

12int team[maxn];//

佇列 13

bool visit[maxn];//

是否在佇列中

14int

n,m,u,v,len,a,e;

1516

void sc(int u)//

求最短路徑

1732}33

}34 visit[p]=false;//

將p標記為沒在佇列中

35 head++;//

head後移,head所指向的元素依次出隊 36}

37 cout<=1;i--)//

輸出路徑

3850

for(int i=1;i<=n;i++)

51 dis[i]=inf;

52 memset(visit,false,sizeof

(visit));

53 memset(team,0,sizeof

(team));

54 cin>>a>>e;//

輸入查詢的起點和終點

55sc(a);

56out

(a,e);

57return0;

58 }

ps:可以用鄰接表實現,效率更高,鄰接矩陣容易炸空間。。。自己選的路,跪著也要走完!!

spfa演算法詳解

粗略講講spfa演算法的原理,spfa演算法是1994年西安交通大學段凡丁提出 是一種求單源最短路的演算法 演算法中需要用到的主要變數 int n 表示n個點,從1到n標號 int s,t s為源點,t為終點 int d n d i 表示源點s到點i的最短路 int p n 記錄路徑 或者說記錄前驅...

spfa演算法及判負環詳解

spfa shortest path faster algorithm 是一種單源最短路徑的演算法,基於bellman ford演算法上由佇列優化實現。也就是說,bellman ford是一種無腦,瘋狂鬆弛的演算法。其複雜度為o nm 可想而知,對於上萬的資料會炸的一塌糊塗。相對而言,spfa顯得就...

Bellman Ford演算法,SPFA演算法

bellman ford 演算法能在更普遍的情況下 存在負權邊 解決單源點最短路徑問題。對於給定的帶權 有向或無向 圖g v,e 其源點為 s,加權函式w是 邊集e 的對映。對圖g執行 bellman ford 演算法的結果是乙個布林值,表明圖中是否存在著乙個從源點s 可達的負權迴路。若不存在這樣的...