【问题标题】:How to find the shortest simple path in a Tree in a linear time?如何在线性时间内找到树中最短的简单路径?
【发布时间】:2011-06-26 00:21:19
【问题描述】:

这是 Vazirani 的算法书中的一个问题

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

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

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

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

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

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

【问题讨论】:

  • Vazirani 近似书?我无法理解问题,树中的每条边都是路径,最小的边是最短路径,你能用这个澄清一下,还是说问题的确切名称太谷歌了?你的意思是找到最短路径树吗?还是树根?
  • @Saeed - 最小的边不一定是最短路径,因为你可以有负权重。
  • 空路径怎么样 - 它是最短的,不是吗?您没有对路径应包含的内容提出单一要求。这没有意义。
  • @Tomas 空路径的权重为零。由单个负权重边组成的路径更短。
  • 提示说这个问题与在树中寻找最大的独立集有关。对这意味着什么有任何想法?

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


【解决方案1】:

这个问题几乎等同于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 时,仅在 pw1[i] != k 时更新 dw2[i]。但是,您为所有孩子递归地调用该函数。在伪代码中看起来像这样:

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])

【讨论】:

  • 看起来很有希望,但我有几点建议:(1)在“计算dw1”下,当你说“后代”时,我相信你的意思是“孩子”(“后代”通常是指所有孩子和孩子的孩子,递归); (2) dw1[i]dw2[i]up[i] 中的每一个的计算都应该在 min{...} 操作中包含 0 以允许路径在此处终止(这样例如不包含负长度边的树将返回0 分); (3) 我相信你对dw2[i] 的计算应该排除最优边缘领先...
  • ... 仅来自顶点i,但在较低级别应包括最佳边缘(询问您是否需要澄清); (4) up[i] 计算可以通过注意每条路径是 2 种中的一种来简化:要么是“直下”,要么包含一个“最上角”(顶点 v 使得 v 的父节点不在路径)——任何在某个顶点 v 包含最高角的路径都可以通过考虑dw1[v] + dw2[v] 来找到,因此up[i] 只需要计算返回根的直线路径上的成本(即up[i] 将是最小值以i 结尾的“直线”路径的成本)。
  • @j_random_hacker - 我刚刚意识到,当你写你的评论并摆脱它时:)。将dw2[k] 放在最低限度是必要的吗?它永远不会小于dw1[k]。前段时间我解决了一个询问诸如what's the shortest path containing q?之类的查询的问题,所以我开始使用up。意识到这里不需要它。
  • @becko:恐怕我实际上并没有看到太多的联系......我知道树中的独立集合可以以大致相似的方式解决,方法是为每个集合计算 2 个值具有 DFS 的节点:以节点 i 为根的子树中使用节点 i 的最大独立集的大小,以及以节点 i 为根但不使用节点 i 的子树中最大独立集的大小。分别调用这些 x(i) 和 y(i)。然后你可以通过对 i 的每个孩子 j 取 1 + sum(y(j)) 来计算 x(i),你可以通过对 i 的每个孩子 j 取 sum(x(j)) 来计算 y(i)。
  • @becko:刚刚发现一个错误!对于 i 的每个孩子 j,y(i) 应该是 sum(max(x(j), y(j))),因为我们只想允许而不是要求孩子包含在独立集中。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-24
  • 1970-01-01
  • 1970-01-01
  • 2013-02-24
  • 2017-01-22
  • 1970-01-01
  • 2022-06-30
相关资源
最近更新 更多