浅谈spfa算法

对Bellman-Ford算法进行优化->SPFA算法

注意到Bellman-Ford算法实际上做了很多无用功。因为每次它都把所有的边枚举一次,而有一些边在上一次枚举中,起始端顶点都没有更新,那么在这一次枚举中,肯定不会进行松弛。那么我们可以使用一个队列来进行活跃点的维护。我们定义在这个队列里的每个元素x都必须满足:d[x]被更新,但是未利用d[x]去更新其它的点。那么初始时把起始点1放进队列里面,然后对它进行松弛操作,并把d值被更新的点放入队列之中,最后把当前这个做完松弛操作的点出队。重复这个操作直到队列中没有元素,那么所有点的d值都被确定了。

这个算法同样可用于有负权边的情况之中。此外,该算法也可以用来判断负权环,具体方法就是如果某一个点入队超过n次,那么判断有负权环。

时间复杂度O(kE),其中k为一个小常数,大致在[3,5]这个范围内。代码实现如下:

procedure spfa;

var

  head,tail,t:longint;

begin

  head:=0; tail:=1;

  list[1]:=1;

  v[1]:=1;                          //初始时把起始点先放进队列里

  while head<>tail do

    begin

      head:=head+1;

      t:=ls[list[head]];

      while t>0 do

        with g[t] do

          begin

            if d[x]+w<d[y] then          //松弛操作

              begin

                d[y]:=d[x]+w;

                if v[y]=0 then //新的点满足未松弛但被更新了d值

                  begin

                    v[y]:=1;

                    tail:=tail+1;

                    list[tail]:=y;

                  end;

              end;

            t:=next;

          end;

     v[list[head]]:=0;

    end;

end;

练习题:洛谷 1144、3371(模板题) //前两题必做,后面选做

       洛谷2296   洛谷1073  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值