最短路徑-SPFA算法
阿新 • • 發佈:2018-10-03
節點 優化 不能 使用 所在 基於 != 發現 沒有
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算法