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

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

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

因此,。


其 状态转移方程如下: 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算法的时间复杂度空间复杂度

Floyd-Warshall算法的描述如下:

for k  1 to n do
  for i  1 to n do
    for j  1 to n do
      if () then
         ;

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

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

大概的代码为:

 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]
经过这么多次迭代后,最后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]
    这样原本空间复杂度O(N3)变为O(N2)了。每次跟新直接在该二位数组上就OK。



你可能感兴趣的:(ACM水题)