适用于:
稀疏图(侧重于对边的处理)。
时间复杂度:
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);
---------------------