如何在线性时间内找到树中最短的简单路径?

时间:2011-02-12 08:22:58

标签: algorithm graph graph-theory dynamic-programming graph-algorithm

这是来自Vazirani的Algorithms book的一个问题

  

此问题的输入是树T,边缘上有整数权重。权重可能是负数,   零或正面。给出一个线性时间算法来找到T中最短的简单路径   path是路径中边的权重之和。如果没有重复顶点,则路径很简单。注意   路径的端点是不受约束的。

     

提示:这与在树中找到最大独立集的问题非常相似。

如何在线性时间内解决这个问题?

这是我的算法,但我想知道它是否是线性时间,因为它与深度优先没什么不同:

  
      
  1. 遍历树(深度优先)
  2.   
  3. 保留索引(节点)
  4.   
  5. 添加值
  6.   
  7. 做(1)直到树的结尾
  8.   
  9. 比较总和并打印路径和总和
  10.   

这个问题与topic类似,但没有确定答案。

1 个答案:

答案 0 :(得分:6)

这个问题几乎与minimum sum subsequence problem相同,可以通过动态编程以类似的方式解决。

我们将使用DF搜索计算以下数组:

dw1[i] = minimum sum achievable by only using node i and its descendants.
pw1[i] = predecessor of node i in the path found for dw1[i].
dw2[i] = second minimum sum achevable by only using node i and its descendants,
         a path that is edge-disjoint relative to the path found for dw1[i].

如果您可以计算这些,请min(dw1[k], dw1[k] + dw2[k])对所有k进行计算。这是因为您的路径将采用以下基本形状之一:

  k              k
  |     or     /   \
  |           /     \
  | 

所有这些都由我们正在服用的金额所涵盖。

计算dw1

从根节点运行DFS。在DFS中,跟踪当前节点及其父节点。在每个节点处,假设其子节点为d1, d2, ... dk。然后是dw1[i] = min(min{dw1[d1] + cost[i, d1], dw1[d2] + cost[i, d2], ..., dw1[dk] + cost[i, dk]}, min{cost[i, dk]})。为叶节点设置dw1[i] = 0。不要忘记使用选定的前任更新pw1[i]

计算dw2

从根节点运行DFS。为dw1做同样的事情,除了从节点i转到其中一个子k时,只有dw2[i]才更新pw1[i] != k。然而,您可以递归地为所有孩子调用该函数。在伪代码中它看起来像这样:

df(node, father)
    dw2[node] = inf
    for all children k of node
        df(k, node)

        if pw1[node] != k
            dw2[node] = min(dw2[node], dw1[k] + cost[node, k], cost[node, k])