Answers:
我们以后期顺序执行深度优先搜索,并按此方式汇总结果,即,我们递归地解决该问题。
对于每个带有子子节点(在搜索树中),有两种情况:u 1,… ,u k
在第二种情况下,我们必须将从开始的一条或两条最长路径合并到一个子树中;这些肯定是最深的叶子。如果则路径的长度为,如果则为,其中多子树高度¹。H (k ) + H (k − 1 ) + 2 k > 1 H (k ) + 1 k = 1 H = { h (T u i)∣ i = 1 ,… ,k }
在伪代码中,算法如下所示:
procedure longestPathLength(T : Tree) = helper(T)[2]
/* Recursive helper function that returns (h,p)
* where h is the height of T and p the length
* of the longest path of T (its diameter) */
procedure helper(T : Tree) : (int, int) = {
if ( T.children.isEmpty ) {
return (0,0)
}
else {
// Calculate heights and longest path lengths of children
recursive = T.children.map { c => helper(c) }
heights = recursive.map { p => p[1] }
paths = recursive.map { p => p[2] }
// Find the two largest subtree heights
height1 = heights.max
if (heights.length == 1) {
height2 = -1
} else {
height2 = (heights.remove(height1)).max
}
// Determine length of longest path (see above)
longest = max(paths.max, height1 + height2 + 2)
return (height1 + 1, longest)
}
}
height1 + height2
这是路径的长度。如果确实是最长的路径,则选择max
。上面的文本中也对此进行了说明,所以我不太明白您的问题吗?当然,您必须进行递归才能找出它是否确实是最长的路径,即使不是,它也不会损害递归的正确性。
height2
显式height1
从考虑中删除,因此如何选择两次相同的孩子?引言中也对此进行了解释。
longestPathHeight(T)
返回一个对(h,d)
,其中h
的高度为T
,d
直径为T
。(对吗?)
这可以通过更好的方式解决。同样,我们可以通过稍微修改数据结构并使用迭代方法将时间复杂度降低到O(n)。对于使用各种数据结构解决此问题的详细分析和多种方法。
这是我想在我的博客文章中解释的摘要:
递归方法-树直径 解决此问题的另一种方法如下。正如我们上面提到的,直径可以
这意味着直径可以理想地由
而且我们知道直径是最长的路径,因此,如果直径位于侧面的任何一方,则取最大值1和2;如果跨越根部,则取3。
迭代法–树径
我们有一棵树,我们需要与每个节点有关的元信息,以便每个节点都知道以下内容:
每个节点获得此信息后,我们需要一个临时变量来跟踪最大路径。当算法完成时,我们在temp变量中具有了直径值。
现在,我们需要以自下而上的方式解决此问题,因为我们不知道根的三个值。但是我们知道叶子的这些价值。
解决步骤
在给定的节点上
以下是仅使用单个DFS遍历返回直径路径的代码。它需要额外的空间来跟踪迄今为止看到的最佳直径以及从树中的特定节点开始的最长路径。这是一种动态编程方法,它基于以下事实:最长的直径路径要么不包括根,要么是根的邻居的两个最长路径的组合。因此,我们需要两个向量来跟踪此信息。
int getDiam(int root, vector<vector<int>>& adj_list, int& height, vector<int>& path, vector<int>& diam) {
visited[root] = true;
int m1 = -1;
int m2 = -1;
int max_diam = -1;
vector<int> best1 = vector<int>();
vector<int> best2 = vector<int>();
vector<int> diam_path = vector<int>();
for(auto n : adj_list[root]) {
if(!visited[n]) {
visited[n] = true;
int _height = 0;
vector<int> path1;
vector<int> path2;
int _diam = getDiam(n, adj_list, _height, path1, path2);
if(_diam > max_diam) {
max_diam = _diam;
diam_path = path2;
}
if(_height > m1) {
m2 = m1;
m1 = _height;
best2 = best1;
best1 = path1;
}
else if(_height > m2) {
m2 = _height;
best2 = path1;
}
}
}
height = m1 + 1;
path.insert( path.end(), best1.begin(), best1.end() );
path.push_back(root);
if(m1 + m2 + 2 > max_diam) {
diam = path;
std::reverse(best2.begin(), best2.end());
diam.insert( diam.end(), best2.begin(), best2.end() );
}
else{
diam = diam_path;
}
return max(m1 + m2 + 2, max_diam);
}