适用于:
稀疏图(侧重于对边的处理)。
时间复杂度:
O(KE),K是常数,平均值为二,E是边数。(因为和边有关,所以不适于稠密图)
来源:
SPFA是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算。
这个算法简单地说就是队列优化的Bellman-Ford,利用了每个点不会更新次数太多的特点发明的此算法。
SPFA在形式上和广度优先搜索非常类似,不同的是广度优先搜索中的一个点出了队列就不可能重新进入队列,但是SPFA中的一个点可能在出队列之后再次被放入队列,也就是说一个点修改过其他的点之后,过了一段时间可能会获得更短的路径,于是再次用来修改其他的点,这样反复进行下去。
优化方法:
1.循环队列(可以降低队列大小)
2.SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j) < dist(i),则将j插入队首,否则插入队尾。
if(!vis[temp]) { if(dis[q[head + 1]] < dis[temp]) //注意小于号不要写反,否则时间会爆 { tail = (++tail - 1) % qxun + 1; q[tail] = temp; } else { q[head] = temp; if(--head == 0) head = qxun; } vis[temp] = 1; }
3.LLL:Large Label Last 策略,设队首元素为i,每次弹出时进行判断,队列中所有dist值的平均值为x,若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将i出对进行松弛操作。
实现:
(伪代码)
dis[i]记录从起点s到i的最短路径,w[i][j]记录连接i,j的边的长度,pre[v]记录前趋。 team[1..n]为队列,头指针head,尾指针tail。 布尔数组exist[1..n]记录一个点是否现在存在队列中。 初始化:dis[s] = 0, dis[v] = oo(v != s), memset(exist, false, sizeof(exist)); 起点入队 team[1] = s; head = 0; tail = 1; exist[s] = true; do { 1.头指针向下移一位,取出指向的点u。 2.exist[u] = false; 已经被取出了队列。 3.for与u相连的所有点v //注意不要去枚举所有点,用链式前向星存储 if(dis[v] > dis[u] + w[u][v]) { dis[v] = dis[u] + w[u][v]; pre[v] = u; if(!exist[v]) //队列中不存在v点,v入队 { 尾指针下移一位,v入队; exist[v] = true; } } }while(head < tail);
---------------------