Floyd最短路径算法

Floyd-Warshall算法 (Floyd-Warshall algorithm)是解决任意两点间的 最短路径 的一种 算法 ,可以正确处理 有向图 或负权的最短路径问题,同时也被用于计算有向图的传递闭包。
通过一个图的权值 矩阵求出它的每两点间的 最短路径 矩阵
从图的带权 邻接矩阵A=[a(i,j)] n×n开始, 递归地进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D(1);又用同样地公式由D(1)构造出D(2);……;最后又用同样的公式由D(n-1)构造出 矩阵D(n)。 矩阵D(n)的i行j列元素便是i号顶点到j号顶点的 最短路径长度,称D(n)为图的 距离矩阵,同时还可引入一个后继节点矩阵path来记录两点间的最短路径。
采用的是(松弛技术),对在i和j之间的所有其他点进行一次松弛。所以 时间复杂度为O(n^3);

D_{i,j,k}为从ij的只以(1..k)集合中的节点为中间节点的最短路径的长度。

  1. 若最短路径经过点k,则D_{i,j,k}=D_{i,k,k-1}+D_{k,j,k-1}
  2. 若最短路径不经过点k,则D_{i,j,k}=D_{i,j,k-1}

因此,D_{i,j,k}=\mbox{min}(D_{i,j,k-1},D_{i,k,k-1}+D_{k,j,k-1})


状态转移方程如下: D[i,j]:=min{ D[i,j],D[i,k]+D[k,j]}
map[i,j]表示i到j的最短距离,K是穷举 i,j的断点,D[n,n]初值应该为0,或者按照题目意思来做。
当然,如果这条路没有通的话,还必须特殊处理,比如没有D[i,k]这条路。

Floyd-Warshall算法的时间复杂度O(N^3)空间复杂度O(N^2)

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};

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

在实际算法中,为了节约空间,可以直接在原来空间上进行迭代,这样空间可降至二维。

大概的代码为:

 for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(ans[k-1][i][k]==无穷大||ans[k-1][k][j]==无穷大)
                {
                    ans[k][i][j]=ans[k-1][i][j]; //保持原来的值,即从i到j允许经过前k个点和允许经过前k-1个节点时最短路径长度相同
                    continue;
                }
                if(ans[k-1][i][j]==无穷大||ans[k-1][i][k]+ans[k-1][k][j]<ans[k-1][i][j])
                {
                    ans[k][i][j]=ans[k-1][i][k]+ans[k-1][k][j];
                }
                else
                {
                    ans[k][i][j]=ans[k-1][i][j];
                }
            }
        }
    }
经过这么多次迭代后,最后a到b的最短路径结果为ans[n][a][b].

与此同时,我们注意到,在通过ans[k-1][i][j]的值来递推求ans[k][i][j]的值时,所有的ans[k][i][j]值将由ans[k-1][i][j]与ans[k-1][i][k]+ans[k-1][k][j]的大小关系来确定,但同时ans[k][i][k]和ans[k][k][j]必定与ans[k-1][i][k]和ans[k-1][k][j]的值是相同的,即这些值不会因为本次更新而发生变化。所以我们将代码简化为:

for(int k=1;k<=n;k++){
    for(int i=1;i<=n;i++){
          for(int j=1;j<=n;j++){
                if(ans[i][k]==无穷大||ans[k][j]==无穷大) continue;
                if(ans[i][j]==无穷大||ans[i][k]+ans[k][j]<ans[i][j])
                  {
                   ans[i][j]=ans[i][k]+ans[k][j];
                  }
           }
     } 
   }
    这样原本空间复杂度O(N3)变为O(N2)了。每次跟新直接在该二位数组上就OK。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值