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 }

 

posted @ 2019-06-14 19:13  DarkValkyrie  阅读(2191)  评论(0编辑  收藏  举报