【问题标题】:Topological sort to find the number of paths to t拓扑排序以查找到 t 的路径数
【发布时间】:2013-08-06 18:17:08
【问题描述】:

我必须开发一种与拓扑排序相关的 O(|V|+|E|) 算法,该算法在有向无环图 (DAG) 中确定从图的每个顶点到 t 的路径数(t 是出度为 0 的节点)。我对 DFS 进行了如下修改:

DFS(G,t):
    for each vertex u ∈ V do
        color(u) = WHITE
        paths_to_t(u) = 0
    for each vertex u ∈ V do
        if color(u) == WHITE then
            DFS-Visit(u,t)

DFS-Visit(u,t):
    color(u) = GREY
    for each v ∈ neighbors(u) do
        if v == t then
            paths_to_t(u) = paths_to_t(u) + 1
        else then
            if color(v) == WHITE then
                DFS-Visit(v)
            paths_to_t(u) = paths_to_t(u) + paths_to_t(v)
    color(u) = BLACK

但我不确定这个算法是否与拓扑排序有关,或者我是否应该从另一个角度重新构建我的工作。

【问题讨论】:

  • 我假设你的图是一个有向无环图(否则就没有必要谈论拓扑排序,也没有关于路径的数量,可能有无数个)
  • @amit 是的,我提出了“有向无环图”的问题。我已编辑添加“DAG”缩写
  • 你的算法是正确的,你确实找到了方法的数量。而且你以一种拓扑正确的方式来做:一旦顶点 u 被涂成黑色,值 path_to_t(u) 就是正确的——它对应于在拓扑排序算法中将顶点推入堆栈。

标签: algorithm graph depth-first-search topological-sort


【解决方案1】:

可以使用动态规划和拓扑排序来完成,如下所示:

Topological sort the vertices, let the ordered vertices be v1,v2,...,vn
create new array of size t, let it be arr
init: arr[t] = 1
for i from t-1 to 1 (descending, inclusive):
    arr[i] = 0  
    for each edge (v_i,v_j) such that i < j <= t:
         arr[i] += arr[j]

完成后,对于[1,t]中的每个iarr[i]表示从vivt的路径数

现在,证明上述主张很容易(与您的算法相比,我不知道它是否正确以及如何证明),它是通过归纳来完成的:

基础:arr[t] == 1,确实有一条从 t 到 t 的路径,即空路径。
假设:对于m &lt; k &lt;= t 范围内的每个k,该声明都是正确的
证明:我们需要证明m 的声明是正确的。
让我们看看vm:(v_m,v_i) 的每个出边。
因此,使用这条边 (v_m,v_i) 的从 v_m 开始到 vt 的路径数。正好是arr[i](归纳假设)。将来自v_m 的所有出边可能性相加,得出从v_mv_t 的路径总数——这正是算法所做的。
因此,arr[m] = #paths from v_m to v_t

QED

时间复杂度:
第一步(拓扑排序)采用O(V+E)
循环遍历所有边一次,所有顶点一次,所以它也是O(V+E)
这给了我们O(V+E)的总复杂度

【讨论】:

  • 我真的不知道动态编程是如何工作的。 :( 我忘了指出算法应该在 O(|V|+|E|)
  • @Stratford 我为算法添加了正确性证明和确保时间复杂度为O(V+E) 的小优化。动态编程是一种技术,我们从“简单”的小案例构建解决方案,直到问题的整体解决方案,这就是拓扑排序之后的循环在伪代码中所做的事情。
  • DP 在这里是多余的。如果他已经在 DFS 中完成了工作,为什么还要麻烦并再次枚举边缘?
  • @amit 是的,DP 方法是正确的,在这里看起来有点矫枉过正。我有一个小评论:您不需要对顶点 v_i 的边进行额外检查。由于顶点是拓扑排序的,v_j 已经在之前的迭代中处理过。因此:对于每条边 (v_i,v_j) arr[i] += arr[j]
  • @Stratford 欢迎您! DP是一个非常强大的工具,掌握这项技术当然是值得的。有很多网站可以练习解决 DP 问题:topcoder、codeforces、SPOJ 等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
  • 2013-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多