板子補完計畫絕讚繼續中(
這篇部落格就來寫一寫spfa(這我居然板子都打錯了一次,我太弱啦!)
先來看一下定義:(引自
首先說明,spfa是一種單源最短路徑演算法,所以以下所說的「某點的最短路徑長度」,指的是「某點到源點的最短路徑長度」。定義從來就不是我們要學習的重點 我們要優雅の打板子!來看這一道比奶牛熱浪還裸的模板題: 然而似乎還是不夠裸..我們讓結構允許出現負環,出現時輸出-1我們記源點為s,由源點到達點i的「當前最短路徑」為d[i],開始時將所有d[i]初始化為無窮大,d[s]則初始化為0。演算法所要做的,就是在執行過程中,不斷嘗試減小d陣列的元素,最終將其中每乙個元素減小到實際的最短路徑。
過程中,我們要維護乙個佇列,開始時將源點置於隊首,然後反覆進行這樣的操作,直到隊列為空:
(1)從隊首取出乙個結點u,掃瞄所有由u結點可以一步到達的結點,具體的掃瞄過程,隨儲存方式的不同而不同;
(2)一旦發現有這樣乙個結點,記為v,滿足d[v] > d[u] + w(u, v),則將d[v]的值減小,減小到和d[u] + w(u, v)相等。其中,w(u, v)為圖中的邊u-v的長度,由於u-v必相鄰,所以這個長度一定已知(不然我們得到的也不叫乙個完整的圖);這種操作叫做鬆弛。
引用內容
鬆弛操作的原理是著名的定理:「三角形兩邊之和大於第三邊」,在資訊學中我們叫它三角不等式。所謂對i,j進行鬆弛,就是判定是否d[j]>d[i]+w[i,j],如果該式成立則將d[j]減小到d[i]+w[i,j],否則不動。
(3)上一步中,我們認為我們「改進了」結點v的最短路徑,結點v的當前路徑長度d[v]相比於以前減小了一些,於是,與v相連的一些結點的路徑長度可能會相應地減小。注意,是可能,而不是一定。但即使如此,我們仍然要將v加入到佇列中等待處理,以保證這些結點的路徑值在演算法結束時被降至最優。當然,如果連線至v的邊較多,演算法執行中,結點v的路徑長度可能會多次被改進,如果我們因此而將v加入佇列多次,後續的工作無疑是冗餘的。這樣,就需要我們維護乙個bool陣列inqueue,來記錄每乙個結點是否已經在佇列中。我們僅將尚未加入佇列的點加入佇列。
演算法能否結束?
對於不存在負權迴路的圖來說,上述演算法是一定會結束的。因為演算法在反覆優化各個最短路徑長度,總有乙個時刻會進入「無法再優化」的局面,此時一旦佇列讀空,演算法就結束了。然而,如果圖中存在一條權值為負的迴路,就糟糕了,演算法會在其上反覆執行,通過「繞圈」來無休止地試圖減小某些相關點的最短路徑值。假如我們不能保證圖中沒有負權迴路,一種「結束條件」是必要的。這種結束條件是什麼呢?思考bellman-ford演算法,它是如何結束的?顯然,最樸素的bellman-ford演算法不管迴圈過程中發生了什麼,一概要迴圈|v|-1遍才肯結束。憑直覺我們可以感到,spfa演算法「更聰明一些」,就是說我們可以猜測,假如在spfa中,乙個點進入佇列——或者說乙個點被處理——超過了|v|次,那麼就可以斷定圖中存在負權迴路了。
就可以用下面的**實現啦
#pragma gcc optimize("o2")#include#include#include#include#include#include#include#include#include#include#include#define n 100001
typedef long long ll;
const int inf=0x3fffffff;
const int maxn=2017;
using namespace std;
inline int read()
while(ch<='9'&&ch>='0')
return f*x;
}struct tsdledge[n*4];
int tot,head[n],inq[n],d[n],n,m,cnt[n];
queueq;
void add(int ui,int vi,int wi)
bool spfa(int u,int n)}}
}return 0;
}int main()
if(spfa(ts,n))
{ cout一期非常蒟蒻的模板總結 以上desu
最短路 SPFA演算法
spfa 是bellman ford的佇列優化,時效性相對好,時間複雜度o ke 與bellman ford演算法類似,spfa演算法採用一系列的鬆弛操作以得到從某乙個節點出發到達圖中其它所有節點的最短路徑。所不同的是,spfa演算法通過維護乙個佇列,使得乙個節點的當前最短路徑被更新之後沒有必要立刻...
最短路演算法 SPFA
單源最短路徑,不可以處理含負權邊的圖但可以用來判斷是否存在負權迴路 複雜度o ke k 2,e 為邊數 bellman ford 演算法的優化,實質與前演算法一樣,但優化的關鍵之處在於 只有那些前面被鬆弛過的點才有可能去鬆弛它們的鄰接點。include include include include...
最短路徑演算法 SPFA
求最短路徑的演算法有許多種,除了排序外,恐怕是oi界中解決同一類問題演算法最多的了。最熟悉的無疑是dijkstra,接著是bellman ford,它們都可以求出由乙個源點向其他各點的最短路徑 如果我們想要求出每一對頂點之間的最短路徑的話,還可以用floyd warshall。spfa是這篇日誌要寫...