这是来自Vazirani的Algorithms book的一个问题
此问题的输入是树T,边缘上有整数权重。权重可能是负数, 零或正面。给出一个线性时间算法来找到T中最短的简单路径 path是路径中边的权重之和。如果没有重复顶点,则路径很简单。注意 路径的端点是不受约束的。
提示:这与在树中找到最大独立集的问题非常相似。
如何在线性时间内解决这个问题?
这是我的算法,但我想知道它是否是线性时间,因为它与深度优先没什么不同:
- 遍历树(深度优先)
- 保留索引(节点)
- 添加值
- 做(1)直到树的结尾
- 比较总和并打印路径和总和
醇>
这个问题与topic类似,但没有确定答案。
答案 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])