【问题标题】:Explanation of algorithm - Reach-ability matrix算法解释 - 可达性矩阵
【发布时间】:2015-04-10 19:19:13
【问题描述】:

我发现了以下内容:

给定一个有向图,对于给定图中的所有顶点对 (i, j),找出一个顶点 j 是否可以从另一个顶点 i 到达。

这里可达的意思是有一条从顶点i到j的路径。

可达性矩阵称为图的传递闭包。

图形以邻接矩阵的形式给出,比如'graph[V][V]',如果从顶点 i 到顶点 j 有一条边,或者 i 等于 j,graph[i][j] 为 1 , 否则 graph[i][j] 为 0。

我们可以使用 Floyd Warshall 计算距离矩阵 dist[V][V],如果 dist[i][j] 是无限的,那么 j 是从 i 不可到达的,否则 j 是可到达的并且 dist[i] 的值[j] 将小于 V。

// Prints transitive closure of graph[][] using Floyd Warshall algorithm
void transitiveClosure(int graph[][V])
{
    /* reach[][] will be the output matrix that will finally have the shortest
      distances between every pair of vertices */
    int reach[V][V], i, j, k;
 
    /* Initialize the solution matrix same as input graph matrix. Or
       we can say the initial values of shortest distances are based
       on shortest paths considering no intermediate vertex. */
    for (i = 0; i < V; i++)
        for (j = 0; j < V; j++)
            reach[i][j] = graph[i][j];
 
    /* Add all vertices one by one to the set of intermediate vertices.
      ---> Before start of a iteration, we have reachability values for all
      pairs of vertices such that the reachability values consider only the
      vertices in set {0, 1, 2, .. k-1} as intermediate vertices.
      ----> After the end of a iteration, vertex no. k is added to the set of
      intermediate vertices and the set becomes {0, 1, 2, .. k} */
    for (k = 0; k < V; k++)
    {
        // Pick all vertices as source one by one
        for (i = 0; i < V; i++)
        {
            // Pick all vertices as destination for the
            // above picked source
            for (j = 0; j < V; j++)
            {
                // If vertex k is on a path from i to j,
                // then make sure that the value of reach[i][j] is 1
                reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
            }
        }
    }
 
    // Print the shortest distance matrix
    printSolution(reach);
}

首先,你能解释一下为什么函数的参数是 graph[][V] 而不是 graph[V][V] 吗?

那我们为什么要初始化矩阵,最终每对顶点之间的距离最短,用graph[V][V]?

你能解释一下初始化之后在for循环中做了什么吗?

我们如何编写这个命令:reach[i][j] = reach[i][j] || (reach[i][k] &amp;&amp; reach[k][j]); elsewhise?

编辑:图是布尔矩阵,还是不是?

如果是这样,那么reach不也是一个布尔矩阵吗?

所以如果我们有这个命令: (reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]); ) 如果到达[i][j]=1 然后我们执行这个:reach[i][j]=reach[i][j],否则我们检查 if (reach[i][k] +reach[k][j] ) 是非零的吗?

还是我理解错了?

【问题讨论】:

    标签: algorithm graph floyd-warshall


    【解决方案1】:

    首先,你能解释一下为什么函数的参数是 graph[][V] 而不是 graph[V][V] ?

    它也可以是图[V][V]。我更喜欢 graph[V][V] 因为无论如何这是预期的输入。

    那我们为什么要初始化矩阵,那最终会有 每对顶点之间的最短距离,用图[V][V]?

    那是因为节点 a 和 b 之间的距离肯定最多是 a 和 b 之间的边的值(如果没有边,假设它是无限的)。 例如:如果我们有图,其中 A 和 B 之间有长度为 5 的边,我们肯定知道 A 和 B 之间存在长度为 5 的路径,但是可能存在更短的路径。

    这里有一些重要的事情需要注意。如果您只对可达性感兴趣,那么您并不关心实际距离。在这种情况下,如果不存在任何路径,您可以将值设置为 0,如果存在路径,则设置为 1。

    你能解释一下初始化后做了什么吗? 循环?

    您基本上是在使用动态编程方法。解释很长,在这里阅读:http://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm

    我们如何编写这个命令:reach[i][j] =reach[i][j] || (到达[i][k] && 到达[k][j]);不然呢?

    我们可以写成:reach[i][j] |= (reach[i][k] &&reach[k][j])

    【讨论】:

      【解决方案2】:

      首先,你能解释一下为什么函数的参数是 graph[][V] 而不是 graph[V][V] 吗?

      函数是这样声明的,因此它可以接受一个二维数组,其中一个轴的大小未知。由于邻接矩阵根据定义是方形的,而reach[V][V] 是稍后定义的,我不知道他们为什么要这样定义函数。有关详细信息,请参阅this SO 问题。

      那我们为什么要初始化矩阵,最终每对顶点之间的距离最短,用graph[V][V]?

      graph 定义了可以通过没有中间节点遍历单个边到达每个其他顶点的每个顶点。当我们开始算法时,这些是最短的路径,也是我们知道的从一个顶点到另一个顶点的唯一路径。通常,如果顶点无法通过直接路径彼此到达,graph 会将边定义为零(无连通性)或无限(它们之间的距离大到无法通过)。

      你能解释一下初始化后在for循环中做了什么吗?

      首先,理解这一行:

      reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
      

      它问:“顶点 i 是否可以从顶点 j 到达?或者可以通过中间顶点 k 从顶点 j 到达顶点 i 吗?”

      这就解释了为什么需要三个 for 循环。为什么它们的顺序是这样的?

      想象一下,你有与上面相同的行,for 循环的顺序如下:

      for i
        for j
          for k
      

      如果是这种情况,对于每对顶点 (i,j),您将检查这两个顶点是否可以通过某个中间顶点 k 连接。然后你就退出了。

      但是如果你必须通过 两个 中间顶点才能从 (i,j) 得到。上述for循环的排序可能不会发现这种可能性。

      相反,我们将 k 在 outside 的 for 循环排序,因此,找到 all k 为中间点的点对。然后我们对每个可能的中间点 k 执行此操作。有严格的方法可以证明这样做可以让您考虑两点之间的所有路径,但是,如果您稍微考虑一下,我认为您会发现它在直觉上是正确的。

      我们如何编写这个命令:reach[i][j] =reach[i][j] || (到达[i][k] && 到达[k][j]);不然呢?

      正如另一位评论员所说,您可以这样写:

      reach[i][j] |= (reach[i][k] && reach[k][j])
      

      你也可以写:

      reach[i][j] = min(reach[i][j], reach[i][k]+reach[k][j])
      

      这将找到两个顶点之间的最短路径的长度,前提是您的输入图使用无穷大来表示未连接的顶点。

      请注意:

      reach[i][j] = max(reach[i][j], reach[i][k]+reach[k][j])
      

      将是一个非常糟糕的主意。在一般图表中找到longest pathNP-hard:我们知道没有好的方法和there probably isn't one。但是,如果你找到了,你不仅会变得富有:整个世界都会在一夜之间改变,你会被永远铭记。

      【讨论】:

      • Richard 如果我想写一个算法,我可以把它作为一个参数:reach[V][V],或者不是?图是布尔矩阵,还是不是?如果是这样,那么到达不是一个布尔矩阵吗?所以如果我们有这个命令: (reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]); ) 并且如果reach[i] [j]=1 然后我们执行这个:reach[i][j]=reach[i][j],否则我们检查 (reach[i][k] +reach[k][j]) 是否为非-零?还是我理解错了?
      • 另外,我想证明一般图中最长的路径是 NP 难的。 stackoverflow.com/questions/29572564/…
      • @evinda,你通过调用transitiveClosure(graph)来调用函数。 graph 指向数据。 [][V] or [V][V]` 位只是告诉编译器数据是如何排列的。 graph 应该是一个布尔矩阵,假设您只对是否存在从一个顶点到另一个顶点的路径感兴趣。
      • @evinda,如果reach[i][j] 为1 或reach[i][k] &amp;&amp; reach[k][j] 为1,则@evinda 在这一行中reach[i][j] = reach[i][j] || (reach[i][k] &amp;&amp; reach[k][j]); reach[i][j] 将为1。另一种写法是:if(reach[i][k] &amp;&amp; reach[k][j]) reach[i][j]=1。跨度>
      • @evinda, reach 也将是一个布尔矩阵。
      猜你喜欢
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 2012-09-17
      • 2021-06-02
      • 2018-09-18
      • 1970-01-01
      • 2013-09-28
      • 2013-07-02
      相关资源
      最近更新 更多