📜  树上的动态规划 | 2套

📅  最后修改于: 2021-09-17 06:50:32             🧑  作者: Mango

给定具有 N 个节点和 N-1 条边的树,找出当树中的任何节点被视为树的根时最大高度

上图表示一棵树有11 个节点10 条边,以及当节点 1 被视为根时为我们提供最大高度的路径。最大高度为 3。

在上图中,当 2 被视为根时,找到的最长路径为红色。一种天真的方法是对每个节点使用 DFS 遍历来遍历树,并在将节点视为树的根时计算最大高度。树的 DFS 遍历的时间复杂度为 O(N)。所有 N 个节点的 DFS 的总时间复杂度为 O(N)*N,即 O(N 2 )

上述问题可以通过在树上使用动态规划来解决为了解决这个问题,为每个节点预先计算两件事。一个是通过它的树枝向下移动到叶子时的最大高度。而另一个将是通过其父级向上移动到任何叶子时的最大高度。
最优子结构:
当节点 i 被视为根时,
in[i]是当我们通过其子树和叶子向下行进时树的最大高度。
此外, out[i]是通过其父节点向上移动时树的最大高度。

in[i] 的计算:

在上图中,已经为每个节点 i 计算了 [i] 中的值。取每个子树的最大值并将 1 添加到该子树的父级。为父树和子树之间的边加 1。使用 DFS 遍历树并将in[i]计算为每个节点的max(in[i], 1+in[child])
out[i] 的计算:

上图显示了所有的 out[i] 值和路径。为了计算 out[i],向上移动到节点 i 的父节点。从节点 i 的父节点移入,有两种方式,一种是在父节点的所有分支中。另一个方向是移动到节点 i 的父节点(称为 parent1)的父节点(称为 parent2 以避免混淆)。通过 parent2 向上的最大高度是out[parent1]本身。通常,out[node i] 为 1+max(out[i], 1+max of all branch)。为节点和父节点之间的边添加 1。

上图解释了当 2 被视为树的根时 out[i] 的计算。节点 2 的分支不计算在内,因为通过该路径的最大高度已经计算并存储在 i[2] 中。向上移动,在这种情况下,2 的父节点,即 1,没有父节点。因此,在计算最大值时考虑除具有节点的分支之外的分支。

上图解释了out[10]的计算。节点 10 的父节点,即 7 有一个父节点和一个分支(在这种情况下正好是一个子节点)。因此,在存在父级和分支的情况下,两者的最大高度已被计算在内。
如果父节点有多个分支,取其中最长的一个计数(不包括节点所在的分支)
计算连接到 parent 的所有分支的最大高度:
in[i] 存储向下移动时的最大高度。无需存储所有分支的长度。只有所有分支中的第一个和第二个最大长度才能给出答案。由于使用的算法基于 DFS,因此将考虑连接到父节点的所有分支,包括具有节点的分支。如果这样得到的第一个最大路径与in[i]相同,则maximum1就是节点i所在分支的长度。在这种情况下,我们最长的路径将是maximum2。
in[i] 和 out[i] 的递归关系:

下面是上述想法的实现:

C++
// C++ code to find the maximum path length
// considering any node as root
#include 
using namespace std;
const int MAX_NODES = 100;
 
int in[MAX_NODES];
int out[MAX_NODES];
 
// function to pre-calculate the array in[]
// which stores the maximum height when travelled
// via branches
void dfs1(vector v[], int u, int parent)
{
    // initially every node has 0 height
    in[u] = 0;
 
    // traverse in the subtree of u
    for (int child : v[u]) {
 
        // if child is same as parent
        if (child == parent)
            continue;
 
        // dfs called
        dfs1(v, child, u);
 
        // recursively calculate the max height
        in[u] = max(in[u], 1 + in[child]);
    }
}
 
// function to pre-calculate the array ouut[]
// which stores the maximum height when traveled
// via parent
void dfs2(vector v[], int u, int parent)
{
    // stores the longest and second
    // longest branches
    int mx1 = -1, mx2 = -1;
 
    // traverse in the subtress of u
    for (int child : v[u]) {
        if (child == parent)
            continue;
 
        // compare and store the longest
        // and second longest
        if (in[child] >= mx1) {
            mx2 = mx1;
            mx1 = in[child];
        }
 
        else if (in[child] > mx2)
            mx2 = in[child];
    }
 
    // traverse in the subtree of u
    for (int child : v[u]) {
        if (child == parent)
            continue;
 
        int longest = mx1;
 
        // if longest branch has the node, then
        // consider the second longest branch
        if (mx1 == in[child])
            longest = mx2;
 
        // recursively calculate out[i]
        out[child] = 1 + max(out[u], 1 + longest);
 
        // dfs function call
        dfs2(v, child, u);
    }
}
 
// function to print all the maximum heights
// from every node
void printHeights(vector v[], int n)
{
    // traversal to calculate in[] array
    dfs1(v, 1, 0);
 
    // traversal to calculate out[] array
    dfs2(v, 1, 0);
 
    // print all maximum heights
    for (int i = 1; i <= n; i++)
        cout << "The maximum height when node "
             << i << " is considered as root"
             << " is " << max(in[i], out[i])
             << "\n";
}
 
// Driver Code
int main()
{
    int n = 11;
    vector v[n + 1];
 
    // initialize the tree given in the diagram
    v[1].push_back(2), v[2].push_back(1);
    v[1].push_back(3), v[3].push_back(1);
    v[1].push_back(4), v[4].push_back(1);
    v[2].push_back(5), v[5].push_back(2);
    v[2].push_back(6), v[6].push_back(2);
    v[3].push_back(7), v[7].push_back(3);
    v[7].push_back(10), v[10].push_back(7);
    v[7].push_back(11), v[11].push_back(7);
    v[4].push_back(8), v[8].push_back(4);
    v[4].push_back(9), v[9].push_back(4);
 
    // function to print the maximum height from every node
    printHeights(v, n);
 
    return 0;
}


Java
// Java code to find the maximum path length
// considering any node as root
import java.io.*;
import java.util.*;
 
class GFG{
 
static final int MAX_NODES = 100;
static int in[] = new int[MAX_NODES];
static int out[] = new int[MAX_NODES];
 
// Function to pre-calculate the array in[]
// which stores the maximum height when travelled
// via branches
static void dfs1(ArrayList> v,
                 int u, int parent)
{
     
    // Initially every node has 0 height
    in[u] = 0;
 
    // Traverse in the subtree of u
    for(int j = 0; j < v.get(u).size(); j++)
    {
        int child = v.get(u).get(j);
         
        // If child is same as parent
        if (child == parent)
            continue;
 
        // dfs called
        dfs1(v, child, u);
 
        // Recursively calculate the max height
        in[u] = Math.max(in[u], 1 + in[child]);
    }
}
 
// Function to pre-calculate the array ouut[]
// which stores the maximum height when traveled
// via parent
static void dfs2(ArrayList> v,
                 int u, int parent)
{
     
    // Stores the longest and second
    // longest branches
    int mx1 = -1, mx2 = -1;
 
    // Traverse in the subtress of u
    for(int j = 0; j < v.get(u).size(); j++)
    {
        int child = v.get(u).get(j);
        if (child == parent)
            continue;
 
        // Compare and store the longest
        // and second longest
        if (in[child] >= mx1)
        {
            mx2 = mx1;
            mx1 = in[child];
        }
 
        else if (in[child] > mx2)
            mx2 = in[child];
    }
 
    // Traverse in the subtree of u
    for(int j = 0; j < v.get(u).size(); j++)
    {
        int child = v.get(u).get(j);
        if (child == parent)
            continue;
 
        int longest = mx1;
 
        // If longest branch has the node, then
        // consider the second longest branch
        if (mx1 == in[child])
            longest = mx2;
 
        // Recursively calculate out[i]
        out[child] = 1 + Math.max(out[u], 1 + longest);
 
        // dfs function call
        dfs2(v, child, u);
    }
}
 
static void addEdge(ArrayList> adj,
                    int u, int v)
{
    adj.get(u).add(v);
    adj.get(v).add(u);
}
 
// Function to print all the maximum heights
// from every node
static void printHeights(ArrayList> v,
                         int n)
{
     
    // Traversal to calculate in[] array
    dfs1(v, 1, 0);
 
    // Traversal to calculate out[] array
    dfs2(v, 1, 0);
 
    // Print all maximum heights
    for(int i = 1; i < n; i++)
        System.out.println(
            "The maximum height when node " + i +
            " is considered as root is " +
            Math.max(in[i], out[i]));
}
 
// Driver Code
public static void main(String[] args)
{
     
    // Creating a graph with 11 vertices
    int V = 12;
    ArrayList> adj = new ArrayList>(V + 1);
    for(int i = 0; i < V; i++)
        adj.add(new ArrayList());
 
    // Initialize the tree given in the diagram
    addEdge(adj, 1, 2);
    addEdge(adj, 1, 3);
    addEdge(adj, 1, 4);
    addEdge(adj, 2, 5);
    addEdge(adj, 2, 6);
    addEdge(adj, 3, 7);
    addEdge(adj, 7, 10);
    addEdge(adj, 7, 11);
    addEdge(adj, 4, 8);
    addEdge(adj, 4, 9);
 
    // Function to print the maximum height
    // from every node
    printHeights(adj, V);
}
}
 
// This code is contributed by decoding


Python3
# Python3 code to find the maximum path length
# considering any node as root
inn = [0] * 100
out = [0] * 100
 
# function to pre-calculate the array inn[]
# which stores the maximum height when travelled
# via branches
def dfs1(v, u, parent):
    global inn, out
     
    # initially every node has 0 height
    inn[u] = 0
 
    # traverse in the subtree of u
    for child in v[u]:
 
        # if child is same as parent
        if (child == parent):
            continue
 
        # dfs called
        dfs1(v, child, u)
 
        # recursively calculate the max height
        inn[u] = max(inn[u], 1 + inn[child])
 
# function to pre-calculate the array ouut[]
# which stores the maximum height when traveled
# via parent
def dfs2(v, u, parent):
    global inn, out
     
    # stores the longest and second
    # longest branches
    mx1, mx2 = -1, -1
 
    # traverse in the subtress of u
    for child in v[u]:
        if (child == parent):
            continue
 
        # compare and store the longest
        # and second longest
        if (inn[child] >= mx1):
            mx2 = mx1
            mx1 = inn[child]
 
        elif (inn[child] > mx2):
            mx2 = inn[child]
 
    # traverse in the subtree of u
    for child in v[u]:
        if (child == parent):
            continue
 
        longest = mx1
 
        # if longest branch has the node, then
        # consider the second longest branch
        if (mx1 == inn[child]):
            longest = mx2
 
        # recursively calculate out[i]
        out[child] = 1 + max(out[u], 1 + longest)
 
        # dfs function call
        dfs2(v, child, u)
 
# function to prall the maximum heights
# from every node
def printHeights(v, n):
    global inn, out
     
    # traversal to calculate inn[] array
    dfs1(v, 1, 0)
 
    # traversal to calculate out[] array
    dfs2(v, 1, 0)
 
    # prall maximum heights
    for i in range(1, n + 1):
        print("The maximum height when node", i, "is considered as root is", max(inn[i], out[i]))
 
# Driver Code
if __name__ == '__main__':
    n = 11
    v = [[] for i in range(n + 1)]
 
    # initialize the tree given in the diagram
    v[1].append(2)
    v[2].append(1)
    v[1].append(3)
    v[3].append(1)
    v[1].append(4)
    v[4].append(1)
    v[2].append(5)
    v[5].append(2)
    v[2].append(6)
    v[6].append(2)
    v[3].append(7)
    v[7].append(3)
    v[7].append(10)
    v[10].append(7)
    v[7].append(11)
    v[11].append(7)
    v[4].append(8)
    v[8].append(4)
    v[4].append(9)
    v[9].append(4)
 
    # function to print the maximum height from every node
    printHeights(v, n)
 
# This code is contributed by mohit kumar 29.


Javascript


输出 :
The maximum height when node 1 is considered as root is 3
The maximum height when node 2 is considered as root is 4
The maximum height when node 3 is considered as root is 3
The maximum height when node 4 is considered as root is 4
The maximum height when node 5 is considered as root is 5
The maximum height when node 6 is considered as root is 5
The maximum height when node 7 is considered as root is 4
The maximum height when node 8 is considered as root is 5
The maximum height when node 9 is considered as root is 5
The maximum height when node 10 is considered as root is 5
The maximum height when node 11 is considered as root is 5

时间复杂度: O(N)
辅助空间: O(N)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程