所有对具有单矩阵的最短路径算法逻辑

时间:2011-12-13 11:33:12

标签: algorithm binary-tree

我正在阅读关于数据结构中的所有对最短路径算法和Wessis书中的算法分析

  

如下面的伪C代码所示,当k> 0我们可以写一个简单的   Dk,i,j的公式。从vi到vj的最短路径,仅使用v1,   v2 ,. 。 。 ,作为中间体的vk是最短的路径   不要使用vk作为中间体,或者包含合并   两条路径vi vk和vk vj,每条路径仅使用第一个k -   1个顶点作为中间体。这导致公式

     

Dk,i,j = min {Dk - 1,i,j,Dk - 1,i,k + Dk - 1,k,j}

     

时间要求再次为O(| V | 3)。因为第k阶段   仅取决于(k-1)st阶段,它似乎只有两个| V | X   | V |需要维护矩阵。但是,使用k作为   用k开始或结束的路径上的中间顶点不会   除非存在负循环,否则改善结果。因此,只有一个   矩阵是必要的,因为Dk-1,i,k = Dk,i,k和Dk-1,k,j = Dk,k,j,   这意味着右边的任何条款都没有改变价值和   需要得救。

我的问题:

  1. 作者的意思是“然而,使用k作为以k开头或结尾的路径上的中间顶点不会改善结果,除非 有一个负面的循环“?

  2. 作者如何得出“Dk-1,i,k = Dk,i,k和Dk-1,k,j = Dk,k,j”?

  3. 任何人都可以用简单的例子解释

    /* Compute All-Shortest Paths */
    
    /* A[] contains the adjacency matrix */
    
    /* with A[i][i] presumed to be zero */
    
    /* D[] contains the values of shortest path */
    
    /* |V | is the number of vertices */
    
    /* A negative cycle exists iff */
    
    /* d[i][j] is set to a negative value at line 9 */
    
    /* Actual Path can be computed via another procedure using path */
    
    /* All arrays are indexed starting at 0 */
    
    
    
    void
    
    all_pairs( two_d_array A, two_d_array D, two_d_array path )
    
    {
    
    int i, j, k;
    
    
    
    /*1*/        for( i = 0; i < |V |; i++ ) /* Initialize D and path */
    
    /*2*/               for( j = 0; j < |V |; j++ )
    
    {
    
    /*3*/                  D[i][j] = A[i][j];
    
    /*4*/                  path[i][j] = NOT_A_VERTEX;
    
    }
    
    /*5*/        for( k = 0; k < |v |; k++ )
    
    /* Consider each vertex as an intermediate */
    
    /*6*/        for( i = 0; i < |V |; i++ )
    
    /*7*/                  for( j = 0; j < |V |; j++ )
    
    /*8*/                       if( d[i][k] + d[k][j] < d[i][j] )
    
    /*update min */
    
    {
    
    /*9*/                            d[i][j] = d[i][k] + d[k][j];
    
    /*10*/                           path[i][j] = k;
    
    }
    
    }
    

1 个答案:

答案 0 :(得分:2)

以下是您问题的答案。

1)Floyd算法利用动态规划递推方程来确定顶点之间的所有对最短路径;重复是基于以下事实:为了找到几个顶点 i j 之间的最短路径,你必须检查是否直接从 i < / em>到 j 比从 i 到中间顶点 k 然后从 k 更便宜Ĵ。您检查所有顶点 i j k ,以便复杂度为O( n ^ 3 )。现在考虑一下:如果所有权重都是非负的,那么最短路径的概念就很明确了。相反,如果存在负循环,这个概念就没有意义了。为什么?因为如果在从顶点 i 到顶点 j 的路径上发现负循环,那么您可以根据需要遍历循环次数,并且每次都可以遍历循环,相应路径的成本降低,因为属于循环的边缘上的权重是负的。因此,负循环显然会改善最短路径的成本(成本降低)。因此,如果允许边缘上的负权重,则能够检测负循环非常重要。 Floyd算法假设边缘为正,但能够检测到负循环。

2)递归方程式如下,略微简化了您的符号:

d[i, j] <- min(d[i, j], d[i, k] + d[k, j])

实际使用它如下面的伪代码

所示
for k <- 0 to n-1
   for i<- 0 to n-1
      for j <- 0 to n-1
         d[i, j] <- min(d[i, j], d[i, k] + d[k, j])

d [i,j]的每次更新都需要访问d [i,k]和d [k,j],因此作者要问:如果更新d [i,j]需要值d [i,k] ]和d [k,j]我们如何确定在 k -th迭代期间已经计算了这些值?我们如何确保在 k -th迭代期间这些值不会发生变化?

实际上,这些值在 k -th迭代期间不能改变,因此没有功能依赖性。这就是原因。实际上,在迭代 k 期间,对d [i,k]的更新采用

形式
d[i, k] <- min(d[i, k], d[i, k] + d[k, k])

但是d [k,k]为零,因此d [i,k]不会改变。

同样,d [k,j]的更新是

d[k, j] <- min(d[k, j], d[k, k] + d[k, j])

这样d [k,j]也不会改变。