SPFA的優化


【為什么要優化】

關於SPFA,他死了(懂的都懂)

 

進入正題。。。

 

一般來說,我們有三種優化方法。

 

SLF優化:

SLF優化,即 Small Label First  策略,使用 雙端隊列 進行優化。

一般可以優化15%~20%,在競賽中比較常用。

設從 u 擴展出了 v ,隊列中隊首元素為 k ,若 dis[ v ] < dis[ k ] ,則將 v 插入隊首,否則插入隊尾。

注:隊列為空時直接插入隊尾。

 1 deque<int> q;  2 
 3 inline void spfa(int x)  4 {  5     memset(d,0x3f,sizeof(d));  6     memset(v,0,sizeof(v));  7     d[x]=0;v[x]=1;  8  q.push_back(x);  9     while(q.size()) 10  { 11         int index=q.front();q.pop_front(); 12         v[index]=0; 13         for(int i=head[index];i;i=g[i].next){ 14             int y=g[i].ver,z=g[i].edge; 15             if(d[y]>d[index]+z){ 16                 d[y]=d[index]+z; 17                 if(!v[y]){ 18                     if(!q.empty()&&d[y]>=d[q.front()]) q.push_back(y); 19                     else q.push_front(y); 20                     v[y]=1; 21  } 22  } 23  } 24  } 25 }

 

LLL優化:

LLL優化,即 Large Label Last  策略,使用 雙端隊列 進行優化。

一般用SLF+LLL可以優化50%左右,但是在競賽中並不常用LLL優化。(所以我就懶得寫了,這是從這個大佬那里嫖來的

設隊首元素為 k ,每次松弛時進行判斷,隊列中所有 dis 值的平均值為 x 。

若 dist[ k ] > x ,則將 k 插入到隊尾,查找下一元素,直到找到某一個 k 使得 dis[ k ] <= x ,則將 k 出隊進行松弛操作。

 1 void spfa(){
 2     int u,v,num=0;
 3     long long x=0;
 4     list<int> q;
 5     for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
 6     path[s]=0;
 7     vis[s]=true;
 8     q.push_back(s);
 9     num++;
10     while(!q.empty()){
11         u=q.front();
12         q.pop_front();
13         num--;x-=path[u];
14         while(num&&path[u]>x/num){
15             q.push_back(u);
16             u=q.front();
17             q.pop_front();
18         }
19         vis[u]=false;
20         for(int i=head[u];i;i=a[i].next){
21             v=a[i].to;
22             if(relax(u,v,a[i].w)&&!vis[v]){
23                 vis[v]=true;
24                 if(!q.empty()&&path[v]<path[q.front()])q.push_front(v);
25                 else q.push_back(v);
26                 num++;x+=path[v];
27             }
28         }
29     }
30     for(int i=1;i<=n;i++)printf("%d ",path[i]);
31     printf("\n");
32 }

 

DFS優化:

這種優化顧名思義,就是用dfs的思想代替bfs的思想來優化Bellman-Ford。

常常用於判斷正/負環,時間復雜度可以達到O(m)(m是邊)。思路是,我們每一次dfs的時候如果走回之前dfs過的點,那就是有環,除了這個dfs的標記,我們還可以打另一個vis數組記錄更新過權值的節點,以后就不必重復更新,大大降低復雜度。

不過如果無環的話,那還是上面那兩種優化稍微適用一點。代碼比較短,但是不好擴展。

 1 inline bool spfa(int x)
 2 {
 3     dfs[x]=1;
 4     for(int i=head[x];i;i=g[i].next)
 5     {
 6         int y=g[i].ver,z=g[i].edge;
 7         if(!v[y]||d[y]<d[x]+z){
 8             if(dfs[y]) return 0;
 9             v[y]=1;
10             d[y]=d[x]+z;
11             if(!spfa(y)) return 0;
12         }
13     }
14     dfs[x]=0;
15     return 1;
16 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM