1. 程式人生 > >SPFA的兩個優化

SPFA的兩個優化

splay hid while tar pty += 最短路 9.png empty

評測題:洛谷【模板】單源最短路徑

不加任何優化:

技術分享圖片
 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

技術分享圖片

SPFA的兩個優化