jquave 发表于 2022-8-29 10:17

算法:浅谈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]
查看完整版本: 算法:浅谈SPFA算法及其优化