【发布时间】:2011-02-21 02:20:57
【问题描述】:
更新
我制定了一个我认为在 O(n*k) 运行时间内运行的算法。下面是伪代码:
routine heaviestKPath( T, k )
// create 2D matrix with n rows and k columns with each element = -∞
// we make it size k+1 because the 0th column must be all 0s for a later
// function to work properly and simplicity in our algorithm
matrix = new array[ T.getVertexCount() ][ k + 1 ] (-∞);
// set all elements in the first column of this matrix = 0
matrix[ n ][ 0 ] = 0;
// fill our matrix by traversing the tree
traverseToFillMatrix( T.root, k );
// consider a path that would arc over a node
globalMaxWeight = -∞;
findArcs( T.root, k );
return globalMaxWeight
end routine
// node = the current node; k = the path length; node.lc = node’s left child;
// node.rc = node’s right child; node.idx = node’s index (row) in the matrix;
// node.lc.wt/node.rc.wt = weight of the edge to left/right child;
routine traverseToFillMatrix( node, k )
if (node == null) return;
traverseToFillMatrix(node.lc, k ); // recurse left
traverseToFillMatrix(node.rc, k ); // recurse right
// in the case that a left/right child doesn’t exist, or both,
// let’s assume the code is smart enough to handle these cases
matrix[ node.idx ][ 1 ] = max( node.lc.wt, node.rc.wt );
for i = 2 to k {
// max returns the heavier of the 2 paths
matrix[node.idx][i] = max( matrix[node.lc.idx][i-1] + node.lc.wt,
matrix[node.rc.idx][i-1] + node.rc.wt);
}
end routine
// node = the current node, k = the path length
routine findArcs( node, k )
if (node == null) return;
nodeMax = matrix[node.idx][k];
longPath = path[node.idx][k];
i = 1;
j = k-1;
while ( i+j == k AND i < k ) {
left = node.lc.wt + matrix[node.lc.idx][i-1];
right = node.rc.wt + matrix[node.rc.idx][j-1];
if ( left + right > nodeMax ) {
nodeMax = left + right;
}
i++; j--;
}
// if this node’s max weight is larger than the global max weight, update
if ( globalMaxWeight < nodeMax ) {
globalMaxWeight = nodeMax;
}
findArcs( node.lc, k ); // recurse left
findArcs( node.rc, k ); // recurse right
end routine
让我知道你的想法。欢迎反馈。
我认为提出了两个简单的算法,可以在加权二叉树中找到最重的长度约束路径。首先,算法描述如下:给定一个带权边的n-顶点二叉树,取值k,求长度为k的最重路径。
对于这两种算法,我都需要一个对所有顶点的引用,所以我只需简单地遍历树以引用所有顶点,每个顶点都引用它的左、右和父节点树中的节点。
算法 1 对于这个算法,我基本上计划从树中的每个节点运行 DFS,同时考虑到固定的路径长度。此外,由于我正在寻找的路径有可能从左子树到根到右子树,我将不得不在每个节点上考虑 3 个选择。但这会导致 O(n*3^k) 算法,我不喜欢这样。
算法 2 我本质上是在考虑使用Dijkstra's Algorithm 的修改版本来考虑固定的路径长度。由于我正在寻找最重的并且 Dijkstra 算法找到最轻的,因此我计划在开始遍历之前否定所有边缘权重。实际上......这没有任何意义,因为我必须在每个节点上运行 Dijkstra,这似乎并不比上述算法效率高得多。
所以我想我的主要问题有几个。首先,我上面描述的算法是否解决了手头的问题?我不完全确定 Dijkstra 的版本是否会起作用,因为 Dijkstra 的版本适用于正边缘值。
现在,我确信存在更聪明/更有效的算法……什么是更好的算法?我读过“使用脊椎分解来有效地解决树木的长度受限的最重路径问题”,但这真的很复杂,我根本不明白。是否有其他算法可以解决这个问题,可能不如脊椎分解有效但更容易理解?
【问题讨论】:
-
对于 Algo1:请注意 Dijkstra 不适用于负权重。
-
对...但我认为这是关于负循环,即是否同时存在 + 和 - 边缘?为什么它不适用于所有负边?
-
所有负边也可能有负循环......但是,在二叉树的情况下,这可能是不可能的。 Dijkstra 并不适合二叉树。 Dijkstra 回答了从源到任何目的地的最短路径是什么的问题,在二叉树中,任何 2 个顶点之间实际上只有 1 条路径,这对于你想要的来说真的太复杂了。除非,我误解了你所说的二叉树的意思。
-
我认为您的 DFS 想法可行。您从树中的每个节点开始,向下递归 N 层,保持总权重的运行计数。达到第 N 级后,与整体最佳路径进行比较,并在必要时对其进行更新。
-
您的最新算法看起来不错。 :) 一些挑剔:第 9 行似乎并没有像您的评论所建议的那样将整个列设置为 0,只是第 n 个元素。这将修复
fillArcs()中的一个错误,您可以在第一次循环迭代时访问列i-1,并且还可以让您停止traverseToFillMatrix()中的特殊情况列0——只需在for i = 1 to k中进行循环。在findArcs()中,longPath = path[node.idx][k];行可以删除,循环条件i+j == k AND i < k应更改为i <= k(允许纯右侧路径,i+j == k将始终为真)。
标签: algorithm theory binary-tree