SPFA算法
一.算法簡介
SPFA(Shortest Path Faster Algorithm)算法是求單源最短路徑的一種算法,它是Bellman-ford的隊列優化,它是一種十分高效的最短路算法。
很多時候,給定的圖存在負權邊,這時類似Dijkstra等算法便沒有了用武之地,而Bellman-Ford算法的復雜度又過高,SPFA算法便派上用場了。SPFA的復雜度大約是O(kE),k是每個點的平均進隊次數(一般的,k是一個常數,在稀疏圖中小於2)。
但是,SPFA算法穩定性較差,在稠密圖中SPFA算法時間復雜度會退化。
實現方法:建立一個隊列,初始時隊列里只有起始點,在建立一個表格記錄起始點到所有點的最短路徑(該表格的初始值要賦為極大值,該點到他本身的路徑賦為0)。然后執行松弛操作,用隊列里有的點去刷新起始點到所有點的最短路,如果刷新成功且被刷新點不在隊列中則把該點加入到隊列最后。重復執行直到隊列為空。
此外,SPFA算法還可以判斷圖中是否有負權環,即一個點入隊次數超過N。
二.算法圖解
給定一個有向圖,求A~E的最短路。
源點A首先入隊,並且AB松弛
擴展與A相連的邊,B,C 入隊並松弛。
B,C分別開始擴展,D入隊並松弛
D出隊,E入隊並松弛。
E出隊,此時隊列為空,源點到所有點的最短路已被找到,A->E的最短路即為8
以上就是SPFA算法的過程。
三.算法模板
1 #include "bits/stdc++.h" 2 3 using namespace std; 4 const int maxN = 200010 ; 5 struct Edge 6 { 7 int to , next , w ; 8 } e[ maxN ]; 9 10 int n,m,cnt,p[ maxN ],Dis[ maxN ]; 11 int In[maxN ]; 12 bool visited[ maxN ]; 13 14 void Add_Edge ( const int x , const int y , const int z ) 15 { 16 e[ ++cnt ] . to = y ; 17 e[ cnt ] . next = p[ x ]; 18 e[ cnt ] . w = z ; 19 p[ x ] = cnt ; 20 return ; 21 } 22 23 bool Spfa(const int S) 24 { 25 int i,t,temp; 26 queue<int> Q; 27 memset ( visited , 0 , sizeof ( visited ) ) ; 28 memset ( Dis , 0x3f , sizeof ( Dis ) ) ; 29 memset ( In , 0 , sizeof ( In ) ) ; 30 31 Q.push ( S ) ; 32 visited [ S ] = true ; 33 Dis [ S ] = 0 ; 34 35 while( !Q.empty ( ) ) 36 { 37 t = Q.front ( ) ;Q.pop ( ) ;visited [ t ] = false ; 38 for( i=p[t] ; i ; i = e[ i ].next ) 39 { 40 temp = e[ i ].to ; 41 if( Dis[ temp ] > Dis[ t ] + e[ i ].w ) 42 { 43 Dis[ temp ] =Dis[ t ] + e[ i ].w ; 44 if( !visited[ temp ] ) 45 { 46 Q.push(temp); 47 visited[temp]=true; 48 if(++In[temp]>n)return false; 49 } 50 } 51 } 52 } 53 return true; 54 } 55 56 int main ( ) 57 { 58 int S , T ; 59 60 scanf ( "%d%d%d%d" , &n , &m , &S , &T ) ; 61 for(int i=1 ; i<=m ; ++i ) 62 { 63 int x , y , _ ; 64 scanf ( "%d%d%d" , &x , &y , &_ ) ; 65 Add_Edge ( x , y , _ ) ; 66 } 67 68 if ( !Spfa ( S ) ) printf ( "FAIL!\n" ) ; 69 else printf ( "%d\n" , Dis[ T ] ) ; 70 71 return 0; 72 }
(完)