針對 優先級隊列優化過的dijkstra算法 以及 SPFA算法 進行討論
一號選手:優先級隊列優化過的dijkstra算法 (本質:bfs[ 隊列改爲優先級隊列 ] + dis[]數組記錄到達各點的距離 )
先貼出該算法的實現模板:
void dijkstra(int start) {
for(int i=1;i<=T;i++) {
dis[i]=inf;
}
dis[start]=0;
priority_queue<node> pq;
node nd;//臨時存儲變量使用
nd.at=start,nd.len=0;
pq.push(nd);
while(!pq.empty()) {
node fa=pq.top(); pq.pop();
for(int i=0;i<mp[fa.at].size();i++) {
node ch=mp[fa.at][i];
if(fa.len+ch.len<dis[ch.at]) {
dis[ch.at]=fa.len+ch.len;
nd.at=ch.at,nd.len=fa.len+ch.len;
pq.push(nd);
}
}
}
}
1、在沒有負權邊的情況下求某個點到其他所有點的距離
由於沒有負權邊,隊列的top返回當前路徑中最短的一條路徑的可達點,那麼到達該點的路徑一定最短,
所以相同的點不會第二次進入隊列,因爲這行代碼
fa.len+ch.len<dis[ch.at]
點評:耗時非常穩定,時間複雜度爲elogv,在情況1下推薦優先使用。
2、在沒有負權邊的情況下求某個點到一個指定點的距離
由於沒有負權邊,所以可以在目標點進入隊列的時候直接break跳出,即可以得到最短路徑。
點評:在好的情況下可以快速找到結果,最壞情況下也不會耗時超過elogv,情況2下推薦優先使用。
3、有負權邊的情況下求某個點到其他所有點的距離
由於存在負權邊,隊列的top不再是最短路徑了,因爲不知道哪裏冒出一條負權邊可能會打破原先的最短情況。
所以同一個點可能會入隊列多次,並且一定要等到隊列爲空纔可以跳出,否則dis【i】裏的答案不一定正確的。
點評:耗時高昂,在情況3下,非常不推薦使用。
4、在有負權邊的情況下求某個點到一個指定點的距離
由於存在負權邊,所以與情況3一樣,必須要等到隊列爲空纔可以跳出。
點評:非常不推薦使用,即耗時高昂又顯得弱智。
二號選手:SPFA算法 (本質:bfs[ 加一個數組判斷點是否在隊列內 ] + dis[]數組記錄到達各點的距離 )
先貼出該算法的實現模板
void spfa(int start) {
for(int i=0;i<=T;i++) {
dis[i]=inf,has[i]=0;
}
dis[start]=0;
deque<int> dq;
dq.push_back(start);
while(!dq.empty()) {
int fa=dq.front(); dq.pop_front(); has[fa]=0;
for(int i=0;i<mp[fa].size();i++) {
node ch=mp[fa][i];
if(dis[fa]+ch.len<dis[ch.at]) {
dis[ch.at]=dis[fa]+ch.len;
if(!has[ch.at]) {
has[ch.at]=1;
dq.push_back(ch.at);
}
}
}
}
}
是否有負權邊對SPFA算法不影響,直接討論存在負權邊的情況。
1、求某個點到其他所有點的最短路徑
算法效率聽說不錯,但是非常不穩定,算法證明也有問題,自行百度SPFA算法。
點評:聽說不錯,實戰也確實非常優秀,特別是在有負權邊的情況下。
2、某個點到一個指定點的距離
這個與情況1一樣,不管是否存在負權邊,一定要等到隊列爲空纔可以跳出,否則答案不一定正確。
總結:在沒有負權邊的情況下優先考慮dijkstra算法,比較穩定,當然SPFA也非常優秀。
有負權邊的情況下那就使用SPFA算法,總體來說SPFA選手勝出。
最後說明一點, 沒經過 優先級隊列優化的dijkstra算法不能處理負權邊的情況。
最最後,貼出經過 SLF優化 和 LLL優化的 SPFA算法,但是在實測中LLL優化反而增加了耗時。
測試例子是http://lx.lanqiao.cn/problem.page?gpid=T22
代碼模板如下:
void spfa(int start) {
for(int i=0;i<=T;i++) {
dis[i]=inf,has[i]=0;
}
dis[start]=0;
deque<int> dq;
dq.push_back(start);
int sum=0,cnt=1; //LLL優化需要使用的兩個變量
while(!dq.empty()) {
while(dis[dq.front()]*cnt>sum) {//LLL優化
dq.push_back(dq.front());
dq.pop_front();
}
int fa=dq.front(); dq.pop_front();
has[fa]=0;
sum-=dis[fa]; cnt--;
for(int i=0;i<mp[fa].size();i++) {
node ch=mp[fa][i];
if(dis[fa]+ch.len<dis[ch.at]) {
dis[ch.at]=dis[fa]+ch.len;
if(!has[ch.at]) {
has[ch.at]=1;
if(dis[ch.at]<dis[dq.front()]) {//SLF優化
dq.push_front(ch.at);
}else {
dq.push_back(ch.at);
}
sum+=dis[ch.at]; cnt++;
}
}
}
}
}