算法:浅谈SPFA算法及其优化
关于SPFA算法的优化方式这篇随笔讲解信息学奥林匹克竞赛中图论部分的求最短路算法SPFA的两种优化方式。学习这两种优化算法需要有SPFA朴素算法的学习经验。在本随笔中SPFA朴素算法的相关知识将不予赘述。
上课!
No.1 SLF优化(Small Label First)
顾名思义,这种优化采用的方式是把较小元素提前。
就像dijkstra算法的堆优化一样。我们在求解最短路算法的时候是采取对图的遍历,每次求最小边的一个过程,为了寻找最小边,我们需要枚举每一条出边,如果我们一上来就找到这个边,那当然是非常爽的。一次找一次爽,一直找一直爽。所以我们采用了这种优化方式。
具体实现方式是把原来的队列变成双端队列,如果新入队的元素比队首元素还要小,就加入到队首,否则排到队尾。
模板如下:
void spfa()
{
memset(dist,0x3f,sizeof(dist));
memset(v,0,sizeof(v));
deque<int> q;
q.push_back(1);
v=1;
dist=0;
while(!q.empty())
{
int x=q.front();
q.pop_front();
v=0;
for(int i=head;i;i=nxt)
{
int y=to;
if(dist>dist+val)
{
dist>dist+val;
if(v==0)
{
if(dist<=dist)
q.push_front(y);
else
q.push_back(y);
v=1;
}
}
}
}
}
No.2 LLL优化(Large Label Last)
顾名思义,它的策略是把大的元素放到后面。
你会说,这不跟上面的一样么?
不不不,这个优化针对的是出队元素。它的实现过程是:对于每个出队元素,比较它的dist[]和队列中dist的平均值,如果它的dist[]更大,将它弹出放到队尾。以此类推,直至dist小于其平均值。
模板:
void spfa()
{
memset(dis, 0x3f, sizeof(dis));
queue<int> q;
q.push(1);
v = 1;
dist = 0;
cnt = 1;
while(!Q.empty())
{
int x = q.front();
while (dis*cnt > sum)
{
q.pop();
q.push(x);
x = q.front();
}
q.pop();
cnt--;
sum -= dist;
v = 0;
for (int i = head; i ; i=nxt)
{
int y=to;
if (dist > dist + val)
{
dist = dist + val;
if (v==0)
{
q.push(y);
sum += dist;
cnt++;
}
}
}
}
}
No.3 SLF+LLL同时优化!
听名字就很高级。
是的,的确很高级,不仅高级,而且快。
我就直接上模板了。
void spfa()
{
memset(dist, 0x3f, sizeof(dist));
memset(v,0,sizeof(v));
deque<int> q;
q.push_back(1);
v = 1;
dist = 0;
cnt = 1;
while (!q.empty())
{
int x = q.front();
while (cnt*dist > sum)
{
q.pop_back();
q.push_back(x);
x = q.front();
}
q.pop_front();
cnt--;
sum -= dist;
v = 0;
for (int i = head; i ; i=nxt)
{
int y=to;
if (dist > dist + val)
{
dist = dist + val;
if (!v)
{
if (dist <= dist)
q.push_front(y);
else
q.push_back(y);
v = 1;
sum += dist;
cnt++;
}
}
}
}
}
页:
[1]