spfa演算法 最短路徑演算法

2021-07-30 21:48:18 字數 2018 閱讀 4050

粗略講講spfa演算法的原理,spfa演算法是2023年西安交通大學段凡丁提出

是一種求單源最短路的演算法

演算法中需要用到的主要變數

int n;  //表示n個點,從1到n標號

int s,t;  //s為源點,t為終點

int d[n];  //d[i]表示源點s到點i的最短路

int p[n];  //記錄路徑(或者說記錄前驅)

queue q;  //乙個佇列,用stl實現,當然可有手打佇列,無所謂

bool vis[n];   //vis[i]=1表示點i在佇列中 vis[i]=0表示不在佇列中

幾乎所有的最短路演算法其步驟都可以分為兩步

1.初始化

2.鬆弛操作

初始化: d陣列全部賦值為inf(無窮大);p陣列全部賦值為s(即源點),或者賦值為-1,表示還沒有知道前驅

然後d[s]=0;  表示源點不用求最短路徑,或者說最短路就是0。將源點入隊;

(另外記住在整個演算法中有頂點入隊了要記得標記vis陣列,有頂點出隊了記得消除那個標記)

佇列+鬆弛操作

讀取隊頭頂點u,並將隊頭頂點u出隊(記得消除標記);將與點u相連的所有點v進行鬆弛操作,如果能更新估計值(即令d[v]變小),那麼就更新,另外,如果點v沒有在佇列中,那麼要將點v入隊(記得標記),如果已經在佇列中了,那麼就不用入隊

以此迴圈,直到隊空為止就完成了單源最短路的求解

spfa可以處理負權邊

定理: 只要最短路徑存在,上述spfa演算法必定能求出最小值。

證明:每次將點放入隊尾,都是經過鬆弛操作達到的。換言之,每次的優化將會有某個點v的最短路徑估計值d[v]變小。所以演算法的執行會使d越來越小。由於我們假定圖中不存在負權迴路,所以每個結點都有最短路徑值。因此,演算法不會無限執行下去,隨著d值的逐漸變小,直到到達最短路徑值時,演算法結束,這時的最短路徑估計值就是對應結點的最短路徑值。(證畢)

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

判斷有無負環:

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

spfa的兩種寫法,bfs和dfs,bfs判別負環不穩定,相當於限深度搜尋,但是設定得好的話還是沒問題的,dfs的話判斷負環很快

int

spfa_bfs(int

s) }}}

return

ok;}

int

spfa_dfs(int

u)

else

return1;}}

vis[u]=0

;

return0;

}

如果對於spfa演算法還是不理解,那就在看看下面的這篇文章,說的很詳細。

spfa詳解

hdu:略難)

題解:題解

poj:入門)

題解:題解

nyoj:不易  靈活使用spfa)

題解:題解

最短路徑演算法 SPFA

求最短路徑的演算法有許多種,除了排序外,恐怕是oi界中解決同一類問題演算法最多的了。最熟悉的無疑是dijkstra,接著是bellman ford,它們都可以求出由乙個源點向其他各點的最短路徑 如果我們想要求出每一對頂點之間的最短路徑的話,還可以用floyd warshall。spfa是這篇日誌要寫...

SPFA演算法 最短路徑

只要最短路徑存在,spfa演算法必定能求出最小值,spfa對bellman ford演算法優化的關鍵之處在於意識到 只有那些在前一遍鬆弛中改變了距離估計值的點,才可能引起他們的鄰接點的距離估計值的改變。為什麼隊列為空就不改變了呢?就是因為要到下一點必須經過它的前乙個鄰接點。spfa可以處理負權邊。很...

SPFA演算法 最短路徑

spfa是一種求單源最短路的演算法 演算法中需要用到的主要變數 int n 表示n個點,從1到n標號 int s,t s為源點,t為終點 int d n d i 表示源點s到點i的最短路 int p n 記錄路徑 或者說記錄前驅 queue q 乙個佇列,用stl實現,當然可有手打佇列,無所謂 bo...