SPFA的两个优化

评测题:洛谷【模板】单源最短路径

不加任何优化:

 1 queue<int>q;
 2 void spfa(ll s)
 3 {
 4     for(ll i=1;i<=n;i++) d[i]=(ll)(2147483647);
 5     d[s]=0;q.push(s);v[s]=1;
 6     while(!q.empty())
 7     {
 8         ll ff=q.front();q.pop();v[ff]=0;
 9         for(ll i=h[ff];i;i=e[i].ne)
10         {
11             ll rr=e[i].v;
12             if(d[rr]>d[ff]+e[i].c)
13             {
14                 d[rr]=d[ff]+e[i].c;
15                 if(!v[rr]) q.push(rr),v[rr]=1;
16                 
17             }
18         }
19     }
20 }
View Code

==================================================

优化1(SLF:Small Label First):

使用双端队列(详见代码注释)

证明:显然定理 

 1 deque<ll>q;
 2 void spfa(ll s)
 3 {
 4     for(ll i=1;i<=n;i++) d[i]=(ll)(2147483647),v[i]=0;
 5     d[s]=0;q.push_back(s);v[s]=1;//双端队列 
 6     while(!q.empty())
 7     {
 8         ll ff=q.front();q.pop_front();v[ff]=0;
 9         for(ll i=h[ff];i;i=e[i].ne)
10         {
11             ll rr=e[i].v;
12             if(d[rr]>d[ff]+e[i].c)
13             {
14                 d[rr]=d[ff]+e[i].c;
15                 if(!v[rr]) 
16                 {
17                     if(q.empty() || d[rr]>=d[q.front()]) q.push_back(rr);
18                     else q.push_front(rr);
19                     //如果当前点的dis<队列首的dis,就把当前点放在队列首
20                     //让它优先去更新其他点,减少入队次数
21                     //注意,特殊情况,如果队列为空的话,要放在队列为,不然会RE 
22                     v[rr]=1;
23                 }
24             }
25         }
26     }
27 }
View Code

==================================================================================

优化2(LLL:Large Label Last):

使用双端队列,sum为队列中所以元素的dis和,o为队列中元素个数

即x=sum/o;

对于当前点i,如果dis[i]>=x  则将点i插入到队列尾,否则放到队列首。

证明:不会。

 

 1 deque<int>q;
 2 void spfa(ll s)
 3 {
 4     for(ll i=1;i<=n;i++) d[i]=(ll)(2147483647);
 5     d[s]=0;q.push_back(s);v[s]=1;
 6     sum+=d[s];o++;
 7     while(!q.empty())
 8     {
 9         ll ff=q.front();q.pop_front();v[ff]=0;
10         sum-=d[ff];o--;
11         for(ll i=h[ff];i;i=e[i].ne)
12         {
13             ll rr=e[i].v;
14             if(d[rr]>d[ff]+e[i].c)
15             {
16                 d[rr]=d[ff]+e[i].c;
17                 if(!v[rr]) 
18                 {
19                     v[rr]=1;
20                     if(q.empty() || o*d[rr]>=sum) q.push_back(rr);
21                     else q.push_front(rr);
22                     //注意,特殊情况,如果队列为空的话,要放在队列为,不然会RE 
23                 }
24                 
25             }
26         }
27     }
28 }
View Code

=====================================================

两个优化一起上:

 1 bool v[10002];
 2 deque<int>q;
 3 void spfa(ll s)
 4 {
 5     for(ll i=1;i<=n;i++) d[i]=(ll)(2147483647);
 6     d[s]=0;q.push_back(s);v[s]=1;
 7     sum+=d[s];o++;
 8     while(!q.empty())
 9     {
10         ll ff=q.front();q.pop_front();v[ff]=0;
11         sum-=d[ff];o--;
12         for(ll i=h[ff];i;i=e[i].ne)
13         {
14             ll rr=e[i].v;
15             if(d[rr]>d[ff]+e[i].c)
16             {
17                 d[rr]=d[ff]+e[i].c;
18                 if(!v[rr]) 
19                 {
20                     v[rr]=1;
21                     if(q.empty() || d[rr]>=d[q.front()] || o*d[rr]>=sum) 
22                      q.push_back(rr);
23                     else q.push_front(rr);
24                 }
25                 
26             }
27         }
28     }
29 }
View Code

至此,完。

腐草无光,化为萤而跃彩于夏月。

posted @ 2018-02-26 20:46  月亮茶  阅读(273)  评论(0编辑  收藏  举报