Floyd 和 bellman 算法

Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。

Floyd-Warshall算法的时间复杂度为,空间复杂度为。

原理

Floyd-Warshall算法的原理是动态规划

设为从到的只以集合中的节点为中间节点的最短路径的长度。

  1. 若最短路径经过点k,则;
  2. 若最短路径不经过点k,则。

因此,。

在实际算法中,为了节约空间,可以直接在原来空间上进行迭代,这样空间可降至二维。(见下面的算法描述)

算法描述

Floyd-Warshall算法的描述如下:

for k ← 1 to n do

  for i ← 1 to n do

    for j ← 1 to n do

      if (D_{i,k} + D_{k,j} < D_{i,j}) then

        D_{i,j} ← D_{i,k} + D_{k,j};

 

其中表示由点到点的代价,当为 ∞ 表示两点之间没有任何连接。

 

Floyd-warshall 算法总结

1. 初始化时, 将 dp[i][i] 设置为 0

2. i, j 均从 1 开始遍历

3. 从状态转移方程到代码的实现, 最关键的一步是确定最外层的循环变量是谁, 而最外层的循环变量又是从状态转移方程本身推出. 比如在 Floyd 算法中, 状态转移方程是

当 k 在最短路径上时, dp(i, j, k) = dp(i, k, k-1) + dp(k, j, k-1)

当 k 不在最短路径时, dp(i, j, k) = dp(i, j, k-1)

可以转化为 g(k) = f(k, k-1), 因此应该把 k 作为最外层的循环变量

4. 空间压缩. 在求解 dp(i, j, k) 时, 会用到 dp(i, k, k-1) 和 dp(k, j, k-1) 以及 dp(i, j, k-1). 新生成的数据 dp(i, j, k) j != k 不会被重复利用, 因此可以使用二维空间

 

 

Bellmanford 算法

1. 与 Dijsktra 算法的比较. D 是一种贪心算法, 贪心策略为选取未被处理的最短的节点, 理由是该节点有潜力更新某些节点的距离, 使之变得更小, 每次对该节点的出边进行松弛. 而 B 算法简单的对所有的边进行松弛, 可以看出, D 算法进行的运算是 B 算法的子集.  B 算法的优点是不仅可以处理负权边, 还能判断图是否存在负环.

2. 松弛. 松弛实际上是对相邻节点的访问, 第 n 次松弛保证了保证了所有深度为 n 个节点得出了最短路径. 由于图最短路径最深至多是 V-1, 因此 V-1 次松弛即可确定所有点的最短路径

3. 负权环判定. 因为负权环可以无限制的拉低最短路径, 因此在进行第 V 次松弛后, 最短路径值有所减小, 那么可以肯定, 存在负权环

4. 朴素 BellmanFord 算法

procedure BellmanFord(list vertices, list edges, vertex source)

   // 该实现读入边和节点的列表,并向两个数组(distance和predecessor)中写入最短路径信息



   // 步骤1:初始化图

   for each vertex v in vertices:

       if v is source then distance[v] := 0

       else distance[v] := infinity

       predecessor[v] := null



   // 步骤2:重复对每一条边进行松弛操作

   for i from 1 to size(vertices)-1:

       for each edge (u, v) with weight w in edges:

           if distance[u] + w < distance[v]:

               distance[v] := distance[u] + w

               predecessor[v] := u



   // 步骤3:检查负权环

   for each edge (u, v) with weight w in edges:

       if distance[u] + w < distance[v]:

           error "图包含了负权环"

 

5. SPFA 优化

SPFA 是 Shorest Path Faster Algorithm 的简写. SPFA 基于一个事实: 松弛有效的操作必然发生在松弛的前导节点成功松弛的节点上.

用一个队列记录松弛过的节点, 可以减少冗余计算, 将复杂度降低到 o(kE)

Begin

  initialize-single-source(G,s);

  initialize-queue(Q);

  enqueue(Q,s);

  while not empty(Q) do 

    begin

      u:=dequeue(Q);

      for each v∈adj[u] do 

        begin

          tmp:=d[v];

          relax(u,v);

          if (tmp<>d[v]) and (not v in Q) then

            enqueue(Q,v);

        end;

    end;

End;

 

你可能感兴趣的:(floyd)