zoukankan      html  css  js  c++  java
  • SPFA算法

      

      SPFA算法是Bellman_Ford的一种队列改进,减少了不必要的沉余计算;相比于Dijkstra算法的优点是可以用来在负权图上求最短路,且平均情况下复杂度也较优;

      算法思想:用一个队列来从源点开始维护,使得队列中的每个点都与它相连的点进行松弛操作;若松弛成功,则入队;否则开始下一个点的松弛;直到队列为空;

      从上不难看出,其本质就是BFS的过程,核心部分就是松弛;

      和BFS不同的是,bfs时每个点都最多只入队一次,而SPFA算法中每个点可以多次入队;也就是说,一个点在改进其它的点后,本身有可能再次被其它的点改进,然后加入队列再次准备改进其它的点,如此反复迭代......直到所有的点都无法再改进;此时,队列为空。

      SPFA算法是一种求解单源最短路径的算法,也就是说,它可以求解某个点 S 到图中其它所有的点的距离;所以我们用dist[i]来表示 S 到 i 的最短距离。另外,它还可以检查出负环,判断有无负环:若某个点的入队次数超过 V (代表顶点数)次,则存在负环,所以我们用count[i] 来表示 i 点进入队列的次数;

      SPFA算法有两个优化算法 SLF 和 LLL。SLF: Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队尾。 LLL: Large Label Last 策略,设队首元素为i,队列中所有dist值的平均值为x,若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将 i 出队进行松弛操作。SLF 可使速度提高 15 ~ 20%;SLF + LLL 可提高约 50%。 在实际的应用中SPFA的算法时间效率不是很稳定,为了避免最坏情况的出现,通常使用效率更加稳定的Dijkstra算法。

     1 void SPFA(int s)
     2 {
     3     queue<int> Q;
     4     _clr(used, 0);
     5     _clr(dist, INF);    // dist要初始化为INF
     6     used[s] = true;
     7     dist[s] = 0;
     8     Q.push(s);
     9     while(!Q.empty())
    10     {
    11         int u = Q.front();
    12         Q.pop();
    13         used[u] = false;    // u点出队
    14         for(int v=1; v<=cnt; v++)
    15         {
    16             if(dist[u] + edge[u][v] < dist[v])    // 松弛成功
    17             {
    18                 dist[v] = dist[u] + edge[u][v];
    19                 if(!used[v])
    20                 {
    21                     used[v] = true;
    22                     Q.push(v);
    23                 }
    24             }
    25         }
    26     }
    27 }
    View Code

     

  • 相关阅读:
    CodeForces 587A
    矩阵快速幂模板
    LCA模板
    Codeforces Round #226 (Div. 2 )
    Codeforces Round #225 (Div. 2)
    SGU132
    SRM 599 DIV 2
    POJ1038
    SGU223
    POJ1185
  • 原文地址:https://www.cnblogs.com/khan724/p/4100816.html
Copyright © 2011-2022 走看看