SPFA演算法
是一種求單源最短路的演算法
演算法中需要用到的主要變數
int n; //表示n個點,從1到n標號
int s,t; //s為源點,t為終點
int d[N]; //d[i]表示源點s到點i的最短路
int p[N]; //記錄路徑(或者說記錄前驅)
queue <int> 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)
{
queue <int> q;
memset(d,0x3f,sizeof(d));
d[s]=0;
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
q.push(s); vis[s]=1; c[s]=1;
//頂點入隊vis要做標記,另外要統計頂點的入隊次數
int OK=1;
while(!q.empty())
{
int x;
x=q.front(); q.pop(); vis[x]=0;
//隊頭元素出隊,並且消除標記
for(int k=f[x]; k!=0; k=nnext[k]) //遍歷頂點x的鄰接表
{
int y=v[k];
if( d[x]+w[k] < d[y])
{
d[y]=d[x]+w[k]; //鬆弛
if(!vis[y]) //頂點y不在隊內
{
vis[y]=1; //標記
c[y]++; //統計次數
q.push(y); //入隊
if(c[y]>NN) //超過入隊次數上限,說明有負環
return OK=0;
}
}
}
}
return OK;
}
int spfa_dfs(int u)
{
vis[u]=1;
for(int k=f[u]; k!=0; k=e[k].next)
{
int v=e[k].v,w=e[k].w;
if( d[u]+w < d[v] )
{
d[v]=d[u]+w;
if(!vis[v])
{
if(spfa_dfs(v))
return 1;
}
else
return 1;
}
}
vis[u]=0;
return 0;
}
相關文章
- 最短路-SPFA演算法&Floyd演算法演算法
- SPFA演算法模板(C/C++)演算法C++
- 最短路演算法詳解(Dijkstra/SPFA/Floyd)演算法
- 「學習筆記」SPFA 演算法的最佳化筆記演算法
- POJ 1511 Invitation Cards(最短路spfa演算法)演算法
- hdu 4568 spfa 最短路演算法+旅行商問題演算法
- POJ 3592 Instantaneous Transference 圖論演算法tarjan+spfa圖論演算法
- spfa最佳化
- 851. spfa求最短路(用佇列優化bellman——ford演算法)佇列優化演算法
- hdu1874 暢通工程續 Bellman-Ford演算法SPFA演算法
- 演算法專題 | 10行程式碼實現的最短路演算法——Bellman-ford與SPFA演算法行程
- HDU 4460 Friend Chains(map + spfa)AI
- POJ 1511-Invitation Cards(SPFA)
- POJ 1724 ROADS(優先佇列+spfa)佇列
- 【圖論】Python [ numpy, pandas] 實現 基礎能力以及基礎演算法 [ dfs bfs spfa ] 經過較為嚴格測試圖論Python演算法
- POJ 3159-Candies(差分約束系統-SPFA+鄰接表)
- Bellman - Ford, SPFA 學習筆記(含有負權的單源最短路徑)筆記
- 差分約束系統+SPFA/Bellman判斷負權迴路+uva515
- Bellman Ford+SPFA佇列優化(路徑還原 輸出最短路的路徑)佇列優化
- bzoj3875: [Ahoi2014&Jsoi2014]騎士遊戲(spfa+Dp)JS遊戲
- BZOJ 2019 [Usaco2009 Nov]找工作:spfa【最長路】【判正環】
- 2013成都站D題||hdu4784 bfs+DP+priority_queue(思路從spfa得到啟示)
- 【演算法】KMP演算法演算法KMP
- 【JAVA演算法】圖論演算法 -- Dijkstra演算法Java演算法圖論
- 演算法(2)KMP演算法演算法KMP
- 【演算法】遞迴演算法演算法遞迴
- 演算法題:洗牌演算法演算法
- [演算法之回溯演算法]演算法
- Manacher演算法、KMP演算法演算法KMP
- 【演算法】KMP演算法解析演算法KMP
- 介面限流演算法:漏桶演算法&令牌桶演算法演算法
- 前端演算法:快速排序演算法前端演算法排序
- 演算法初探--遞迴演算法演算法遞迴
- BP演算法和LMBP演算法演算法
- 隨機演算法 概率演算法隨機演算法
- STL::演算法::常見演算法演算法
- 前向分步演算法 && AdaBoost演算法 && 提升樹(GBDT)演算法 && XGBoost演算法演算法
- c/c++ 通用的(泛型)演算法 之 只讀演算法,寫演算法,排序演算法C++泛型演算法排序