Algorithm 使用拓扑排序计数路径

Algorithm 使用拓扑排序计数路径,algorithm,dynamic,graph,topological-sort,Algorithm,Dynamic,Graph,Topological Sort,我有一个DAG,我需要计算从任何节点到另一个节点的所有路径,我做了一些研究,发现它可以通过一些拓扑顺序来完成,但到目前为止,解决方案是不完整的或错误的 那么正确的方法是什么呢 谢谢。您可以使用递归计算树/DAG中的所有路径。以下是伪代码: function numPaths(node1, node2): // base case, one path from node to itself if (node1 == node2): return 1 totalPaths

我有一个DAG,我需要计算从任何节点到另一个节点的所有路径,我做了一些研究,发现它可以通过一些拓扑顺序来完成,但到目前为止,解决方案是不完整的或错误的

那么正确的方法是什么呢


谢谢。

您可以使用递归计算树/DAG中的所有路径。以下是伪代码:

function numPaths(node1, node2):
    // base case, one path from node to itself
    if (node1 == node2): return 1

    totalPaths = 0
    for edge in node1.edges:
        nextNode = edge.destinationNode
        totalPaths += numPaths(nextNode, node2)

    return totalPaths
编辑:
解决此问题的一个很好的动态方法是。

您可以使用递归来计算树/DAG中的所有路径。以下是伪代码:

function numPaths(node1, node2):
    // base case, one path from node to itself
    if (node1 == node2): return 1

    totalPaths = 0
    for edge in node1.edges:
        nextNode = edge.destinationNode
        totalPaths += numPaths(nextNode, node2)

    return totalPaths
编辑: 解决这个问题的一个好的动态方法是

看起来太慢了?可以记住它(有些人称之为动态规划)。像这样

memset(d,-1,sizeof(d))// set all of elements of array d to -1 at the very beginning
saya(int i,int j)
{
    if (d[i][j]!=-1) return d[i][j];//d[i][j] has been calculated
    if (i==j) return d[i][j]=1;//trivival cases
    d[i][j]=0;
    for e in i.edges
        d[i][j]+=saya(e.next,j);
    return d[i][j];
}
现在saya(i,j)将返回从i到j的所有路径的数目

看起来太慢了?可以记住它(有些人称之为动态规划)。像这样

memset(d,-1,sizeof(d))// set all of elements of array d to -1 at the very beginning
saya(int i,int j)
{
    if (d[i][j]!=-1) return d[i][j];//d[i][j] has been calculated
    if (i==j) return d[i][j]=1;//trivival cases
    d[i][j]=0;
    for e in i.edges
        d[i][j]+=saya(e.next,j);
    return d[i][j];
}

现在saya(i,j)将返回从i到j的所有路径的数量。

因为这是一个DAG,您可以在O(V+E)时间内对节点进行拓扑排序。假设源顶点是s,然后从s开始以深度优先的方式遍历节点。当我们处理节点U时,假设有一条边U->V,那么V当然还没有被访问(为什么?因为它是一个有向无环图),所以你可以通过节点U以d[U]的方式从s到V,其中d[U]是从s到U的路径数

所以从S到任意节点V的路径数,d[V]=d[x1]+d[x2]+d[x3]++d[xy],其中有像x1->V,x2->V。xy->V


该算法将使用O(V+E)对图形进行拓扑排序,然后计算最多O(V*E)的路径数。您可以使用邻接列表而不是邻接矩阵进一步减少计算O(V+E)路径数的运行时间,这是迄今为止最有效的解决方案。

由于这是DAG,您可以在O(V+E)时间内对节点进行拓扑排序。假设源顶点是s,然后从s开始以深度优先的方式遍历节点。当我们处理节点U时,假设有一条边U->V,那么V当然还没有被访问(为什么?因为它是一个有向无环图),所以你可以通过节点U以d[U]的方式从s到V,其中d[U]是从s到U的路径数

所以从S到任意节点V的路径数,d[V]=d[x1]+d[x2]+d[x3]++d[xy],其中有像x1->V,x2->V。xy->V



该算法将使用O(V+E)对图形进行拓扑排序,然后计算最多O(V*E)的路径数。您可以使用邻接列表而不是邻接矩阵进一步减少计算O(V+E)路径数的运行时间,这是迄今为止最有效的解决方案。

这是我做的第一件事,但似乎太慢了。这就是我研究并发现拓扑排序的原因。为什么拓扑排序能帮助你计算路径?它的目的是将非DAG转换为DAG,而不是简化计数。因为这种简单的递归在某些DAG上做了大量冗余工作。如果你记忆,记忆表最终会按拓扑顺序构建。好的,我明白了。我会尝试解决这个问题。这是我做的第一件事,但似乎太慢了。这就是我研究并发现拓扑排序的原因。为什么拓扑排序能帮助你计算路径?它的目的是将非DAG转换为DAG,而不是简化计数。因为这种简单的递归在某些DAG上做了大量冗余工作。如果你记忆,记忆表最终会按拓扑顺序构建。好的,我明白了。我会设法解决这个问题。你在这里记什么?由于它是一个DAG,i=>j不会出现两次:-)对不起,忽略了自上而下的方法:)你在回忆什么?由于它是DAG,i=>j不会出现两次:-)抱歉,忽略了自上而下的方法:)它必须以相反的方向迭代拓扑排序列表?@bones.felipe:不,从根到叶。但例如,如果我有一个拓扑列表:0-2-1-3,其中除了0->1和2->3之外,它还计算5个否?好的,所以
d[0]=1d[2]=d[2]+d[0]=1
d[1]=d[1]+d[0]=1
。然后我们转到2,从2
d[1]=d[1]+d[2]=2
d[3]=d[3]+d[2]=1
然后我们转到1,它只有1条边1-3,所以
d[3]=d[3]+d[1]=2+1=3
所以从0~>3有3条不同的路径:)它必须以相反的方向迭代拓扑排序列表?@bones.felipe:不,从根到叶。但例如,如果我有一个拓扑列表:0-2-1-3,其中除了0->1和2->3之外,它还计算5个否?好的,所以
d[0]=1d[2]=d[2]+d[0]=1
d[1]=d[1]+d[0]=1
。然后我们转到2,从2
d[1]=d[1]+d[2]=2
d[3]=d[3]+d[2]=1
然后我们转到1,它只有1条边1-3,所以
d[3]=d[3]+d[1]=2+1=3
所以从0~>3有3条不同的路径:)