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

 

 

posted @ 2014-11-15 23:25  无道圣君  阅读(390)  评论(0编辑  收藏  举报