1. 程式人生 > >最短路徑-SPFA算法

最短路徑-SPFA算法

節點 優化 不能 使用 所在 基於 != 發現 沒有

SPFA(Super Programming Festival Algorithm)
其實是 Shortest Path Faster Algorithm啦^^-o-^^

簡單介紹:復雜度只和邊的數量相關,適用邊的數量很少的最短路問題,BELLMAN-FORD算法的一種優化版本。
算法實現是BFS+剪枝構成的。

算法步驟:

基於BFS遍歷,嘗試將(p, q)加入到隊尾的時候,發現隊列中已經存在一個(p, q‘)了,那麽你就可以比較q和q‘:如果q>=q‘,那麽(p, q)這個節點實際上是沒有繼續搜索下去的必要的——算是一種最優化剪枝吧。而如果q<q‘,那麽(p, q‘)也是沒有必要繼續搜索下去的——但是它已經存在於隊列裏了怎麽辦呢?很簡單,將隊列中的(p, q‘)改成(p, q)就可以了!

通過維護一個position[1..N]的數組就可以判斷隊列中是不是存在著一個(p, q‘),如果不在隊列裏就是-1,否則就是所在的位置!

源代碼:

/*
input:點數 N,邊數 M,起點S,終點T,以及M組路線(起點 終點 終點)
*/
#include <stdio.h>
#include <string.h>
#include <queue>

std::queue<int>q;
int e,head[100005],v[2000005],next[2000005],w[2000005];
/*
dis表示距離
用inqi來標識頂點i是不是在隊列中
*/
int dis[100005],inq[100005];
int n,m,s,t,a,b,c;

void add(int a,int b,int c){
    v[e]=b;w[e]=c;next[e]=head[a];
    head[a]=e++;
}

int spfa(int s,int t){
    memset(inq,0,sizeof inq);
    memset(dis,-1,sizeof dis);
    inq[s]=1;dis[s]=0;
    q.push(s);
    while(q.size()){
        int x=q.front();q.pop();inq[x]=0;
        for(int i=head[x];i!=-1;i=next[i]){
            int ww=dis[x]+w[i];
            if(dis[v[i]]==-1 || dis[v[i]]>ww){
                dis[v[i]]=ww;
                if(!inq[v[i]]){
                    inq[v[i]]=1;
                    q.push(v[i]);
                }
            }
        }
    }
    return dis[t];
}

int main(){
    e=0;memset(head,-1,sizeof head);
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);add(b,a,c);
    }
    printf("%d\n",spfa(s,t));
    return 0;
}

*/

Q:
1、權值為負?
可以,而dijkstra無法使用了,但是不能存在負權回路,負權回路存在可以用拓撲排序進行判斷。
2、雙點之間多條路徑?
可以
3、環路?
可以。
4、自環?

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

最短路徑-SPFA算法