SPFA兩個著名優化(SLF和LLL):
SPFA 是按照 FIFO 的原則更新距離的, 沒有考慮到距離標號的作用。
實現中 SPFA 有兩個非常著名的優化: SLF 和 LLL。
SLF: Small Label First 策略. (比較常用)
實現方法:設隊首元素為 , 隊列中要加入節點
, 在
時加到隊首而不是隊尾, 否則和普通的 SPFA 一樣加到隊尾.
LLL: Large Label Last 策略. (不太常用)
設隊列 Q 中的隊首元素為 i,距離標號的平均值為 ,每次出隊時,若
,把 i 移到隊列末尾,如此反復,直到找到一個
使
,將其出隊。
話說某次在群里問過關於SLF優化的實現問題,木人理我。。。
。
網上這方面的資料貌似也不多。。。。
這兩天看到了雙端隊列,然后就突然想起了SLF優化。。自己實現了下,大牛請無視。
以POJ 3259為例,上面的是優化后的,下面的是不加優化的。不加優化的SPFA 跑了157MS,加了SLF優化后跑了94MS。可以看出,使用SLF優化可以節約一部分的時間。
SLF代碼實現(POJ 3259):
1 #include <algorithm>
2 #include <iostream>
3 #include <cstring>
4 #include <cstdio>
5 #include <deque>
6 using namespace std;
7 const int N= 501;
8 const int NN= 100001;
9 const int inf= 0x7fffffff;
10 int n,nu;
11 typedef struct node
12 {
13 int adj,val;
14 struct node *next;
15 };
16 node node[NN],*p[N];
17 int SPFA()
18 {
19 deque< int> qu;
20 int x,i,a,b;
21 int vis[N],dis[N],num[N];
22 struct node *head[N];
23 for(i= 1;i<=n;i++)
24 {
25 vis[i]= 0;
26 num[i]= 0;
27 dis[i]=inf;
28 head[i]=p[i];
29 }
30 dis[ 1]= 0;
31 vis[ 1]= 1;
32 num[ 1]++;
33 qu.push_back( 1);
34 while(!qu.empty())
35 {
36 x=qu.front();
37 qu.pop_front();
38 vis[x]= 0;
39 head[x]=p[x];
40 while(head[x])
41 {
42 a=head[x]->adj;
43 b=head[x]->val;
44 if(dis[a]>dis[x]+b)
45 {
46 dis[a]=dis[x]+b;
47 if(!vis[a])
48 {
49 vis[a]= 1;
50 num[a]++;
51 if(num[a]>=n)
52 return 1;
53 if(!qu.empty())
54 {
55 if(dis[a]>dis[qu.front()])
56 qu.push_back(a);
57 else
58 qu.push_front(a);
59 }
60 else
61 qu.push_back(a);
62 }
63 }
64 head[x]=head[x]->next;
65 }
66 }
67 return 0;
68 }
69 int main()
70 {
71 int t,i,m,w,a,b,c;
72 scanf( " %d ",&t);
73 while(t--)
74 {
75 memset(node, 0, sizeof(node));
76 memset(p, 0, sizeof(p));
77 nu= 0;
78 scanf( " %d%d%d ",&n,&m,&w);
79 for(i= 0;i<m;i++)
80 {
81 scanf( " %d%d%d ",&a,&b,&c);
82 node[nu].adj=b;
83 node[nu].val=c;
84 node[nu].next=p[a];
85 p[a]=&node[nu];
86 nu++;
87 node[nu].adj=a;
88 node[nu].val=c;
89 node[nu].next=p[b];
90 p[b]=&node[nu];
91 nu++;
92 }
93 for(i= 0;i<w;i++)
94 {
95 scanf( " %d%d%d ",&a,&b,&c);
96 node[nu].adj=b;
97 node[nu].val=-c;
98 node[nu].next=p[a];
99 p[a]=&node[nu];
100 nu++;
101 }
102 if(SPFA())
103 puts( " YES ");
104 else
105 puts( " NO ");
106 }
107 return 0;
108 }
2 #include <iostream>
3 #include <cstring>
4 #include <cstdio>
5 #include <deque>
6 using namespace std;
7 const int N= 501;
8 const int NN= 100001;
9 const int inf= 0x7fffffff;
10 int n,nu;
11 typedef struct node
12 {
13 int adj,val;
14 struct node *next;
15 };
16 node node[NN],*p[N];
17 int SPFA()
18 {
19 deque< int> qu;
20 int x,i,a,b;
21 int vis[N],dis[N],num[N];
22 struct node *head[N];
23 for(i= 1;i<=n;i++)
24 {
25 vis[i]= 0;
26 num[i]= 0;
27 dis[i]=inf;
28 head[i]=p[i];
29 }
30 dis[ 1]= 0;
31 vis[ 1]= 1;
32 num[ 1]++;
33 qu.push_back( 1);
34 while(!qu.empty())
35 {
36 x=qu.front();
37 qu.pop_front();
38 vis[x]= 0;
39 head[x]=p[x];
40 while(head[x])
41 {
42 a=head[x]->adj;
43 b=head[x]->val;
44 if(dis[a]>dis[x]+b)
45 {
46 dis[a]=dis[x]+b;
47 if(!vis[a])
48 {
49 vis[a]= 1;
50 num[a]++;
51 if(num[a]>=n)
52 return 1;
53 if(!qu.empty())
54 {
55 if(dis[a]>dis[qu.front()])
56 qu.push_back(a);
57 else
58 qu.push_front(a);
59 }
60 else
61 qu.push_back(a);
62 }
63 }
64 head[x]=head[x]->next;
65 }
66 }
67 return 0;
68 }
69 int main()
70 {
71 int t,i,m,w,a,b,c;
72 scanf( " %d ",&t);
73 while(t--)
74 {
75 memset(node, 0, sizeof(node));
76 memset(p, 0, sizeof(p));
77 nu= 0;
78 scanf( " %d%d%d ",&n,&m,&w);
79 for(i= 0;i<m;i++)
80 {
81 scanf( " %d%d%d ",&a,&b,&c);
82 node[nu].adj=b;
83 node[nu].val=c;
84 node[nu].next=p[a];
85 p[a]=&node[nu];
86 nu++;
87 node[nu].adj=a;
88 node[nu].val=c;
89 node[nu].next=p[b];
90 p[b]=&node[nu];
91 nu++;
92 }
93 for(i= 0;i<w;i++)
94 {
95 scanf( " %d%d%d ",&a,&b,&c);
96 node[nu].adj=b;
97 node[nu].val=-c;
98 node[nu].next=p[a];
99 p[a]=&node[nu];
100 nu++;
101 }
102 if(SPFA())
103 puts( " YES ");
104 else
105 puts( " NO ");
106 }
107 return 0;
108 }