Dynamic Programming on Trees | Set 2 - GeeksforGeeks

26 Jan, 2022
Given a tree with N nodes and N-1 edges, find out the maximum height of the tree when any node in the tree is considered as the root of the tree. 
The above diagram represents a tree with 11 nodes and 10 edges and the path that gives us the maximum height when node 1 is considered as a root. The maximum height is 3.  
In the above diagram, when 2 is considered as a root, then the longest path found is in RED color. A naive approach would be to traverse the tree using DFS traversal for every node and calculate the maximum height when the node is treated as the root of the tree. The time complexity for the DFS traversal of a tree is O(N). The overall time complexity of DFS for all N nodes will be O(N)*N i.e., O(N2).
The above problem can be solved by using Dynamic Programming on Trees. To solve this problem, pre-calculate two things for every node. One will be the maximum height while traveling downwards via its branches to the leaves. While the other will be the maximum height when traveling upwards via its parent to any of the leaves. Optimal Substructure: When node i is considered as a root, in[i] be the maximum height of the tree when we travel downwards via its sub-trees and leaves.Also, out[i] be the maximum height of the tree while traveling upwards via its parent. 
The maximum height of a tree when node i is considered as a root will be max(in[i], out[i]).
Calculation of in[i]:  
In the image above, values in[i] have been calculated for every node i. The maximum of every subtree is taken and added with 1 to the parent of that subtree. Add 1 for the edge between parent and subtree. Traverse the tree using DFS and calculate in[i] as max(in[i], 1+in[child]) for every node. Calculation of out[i]: 
The above diagram shows all the out[i] values and the path. For calculation of out[i], move upwards to the parent of node i. From the parent of node i, there are two ways to move in, one will be in all the branches of the parent. The other direction is to move to the parent(call it parent2 to avoid confusion) of the parent(call it parent1) of node i. The maximum height upwards via parent2 is out[parent1] itself. Generally, out[node i] as 1+max(out[i], 1+max of all branches). Add 1 for the edges between node and parent. 
The above diagram explains the calculation of out[i] when 2 is considered as the root of the tree. The branches of node 2 are not taken into count since the maximum height via that path has already been calculated and stored in i[2]. Moving up, in this case, the parent of 2, i.e., 1, has no parent. So, the branches except for the one which has the node are considered while calculating the maximum.
The above diagram explains the calculation of out[10]. The parent of node 10, i.e., 7 has a parent and a branch(precisely a child in this case). So the maximum height of both has been taken to count in such cases when parent and branches exist. In case of multiple branches of a parent, take the longest of them to count(excluding the branch in which the node lies) Calculating the maximum height of all the branches connected to parent : in[i] stores the maximum height while moving downwards. No need to store all the lengths of branches. Only the first and second maximum length among all the branches will give the answer. Since the algorithm used is based on DFS, all the branches connected to the parent will be considered, including the branch which has the node. If the first maximum path thus obtained is the same as in[i], then maximum1 is the length of the branch in which node i lies. In this case, our longest path will be maximum2.Recurrence relation of in[i] and out[i]:  
in[i] = max(in[i], 1 + in[child]) out[i] = 1 + max(out[parent of i], 1 + longest path of all branches of parent of i) 
Below is the implementation of the above idea: 
C++
Java
Python3
C#
Javascript
// C++ code to find the maximum path length// considering any node as root#include <bits/stdc++.h>using namespace std; vector<int> in,out; // function to pre-calculate the array in[]// which stores the maximum height when travelled// via branchesvoid dfs1(vector<int> 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 parentvoid dfs2(vector<int> 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 nodevoid printHeights(vector<int> 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 Codeint main(){    int n = 11;    vector<int> 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);       // initialise in and out vectors      in.resize(n+1,0);      out.resize(n+1,0);    // function to print the maximum height from every node    printHeights(v, n);     return 0;}
// Java code to find the maximum path length// considering any node as rootimport 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 branchesstatic void dfs1(ArrayList<ArrayList<Integer>> 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 parentstatic void dfs2(ArrayList<ArrayList<Integer>> 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<ArrayList<Integer>> adj,                    int u, int v){    adj.get(u).add(v);    adj.get(v).add(u);} // Function to print all the maximum heights// from every nodestatic void printHeights(ArrayList<ArrayList<Integer>> 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 Codepublic static void main(String[] args){         // Creating a graph with 11 vertices    int V = 12;    ArrayList<ArrayList<              Integer>> adj = new ArrayList<ArrayList<                              Integer>>(V + 1);    for(int i = 0; i < V; i++)        adj.add(new ArrayList<Integer>());     // 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 code to find the maximum path length# considering any node as rootinn = [0] * 100out = [0] * 100 # function to pre-calculate the array inn[]# which stores the maximum height when travelled# via branchesdef 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 parentdef 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 print all the maximum heights# from every nodedef printHeights(v, n):    global inn, out         # traversal to calculate inn[] array    dfs1(v, 1, 0)     # traversal to calculate out[] array    dfs2(v, 1, 0)     # print all 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 Codeif __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.
using System;using System.Collections.Generic; public class GFG{         static 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 branchesstatic void dfs1(List<List<int>> 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[u].Count; j++)    {        int child = v[u][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 parentstatic void dfs2(List<List<int>> 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[u].Count; j++)    {        int child = v[u][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[u].Count; j++)    {        int child = v[u][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(List<List<int>> adj,                    int u, int v){    adj[u].Add(v);    adj[v].Add(u);}  // Function to print all the maximum heights// from every nodestatic void printHeights(List<List<int>> 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++)        Console.WriteLine(            "The maximum height when node " + i +            " is considered as root is " +            Math.Max(In[i], Out[i]));}  // Driver Code         static public void Main (){                 // Creating a graph with 11 vertices    int V = 12;    List<List<int>> adj = new List<List<                              int>>();    for(int i = 0; i < V; i++)        adj.Add(new List<int>());      // 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 avanitrachhadiya2155
<script>// Javascript code to find the maximum path length// considering any node as root     let MAX_NODES = 100; let In = new Array(MAX_NODES);let out=new Array(MAX_NODES);for(let i=0;i<MAX_NODES;i++){    In[i]=0;    out[i]=0;}// Function to pre-calculate the array in[]// which stores the maximum height when travelled// via branchesfunction dfs1(v,u,parent){    // Initially every node has 0 height    In[u] = 0;       // Traverse in the subtree of u    for(let j = 0; j < v[u].length; j++)    {        let child = v[u][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 parentfunction dfs2(v,u,parent){    // Stores the longest and second    // longest branches    let mx1 = -1, mx2 = -1;       // Traverse in the subtress of u    for(let j = 0; j < v[u].length; j++)    {        let child = v[u][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(let j = 0; j < v[u].length; j++)    {        let child = v[u][j];        if (child == parent)            continue;           let 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);    }} function addEdge(adj,u,v){    adj[u].push(v);    adj[v].push(u);} // Function to print all the maximum heights// from every nodefunction printHeights(v,n){    // Traversal to calculate in[] array    dfs1(v, 1, 0);       // Traversal to calculate out[] array    dfs2(v, 1, 0);       // Print all maximum heights    for(let i = 1; i < n; i++)        document.write(            "The maximum height when node " + i +            " is considered as root is " +            Math.max(In[i], out[i])+"<br>");} // Driver Code let V = 12;let adj = new Array(V+1);for(let i = 0; i <= V; i++)    adj[i]=[];      // Initialize the tree given in the diagramaddEdge(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 nodeprintHeights(adj, V);  // This code is contributed by patel2127</script>
  
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
 
 
Time Complexity : O(N) Auxiliary Space : O(N)
 
deepaksati
Akanksha_Rai
pgmreddy
mohit kumar 29
patel2127
nidhi_biet
avanitrachhadiya2155
ashutoshsinghgeeksforgeeks
adnanirshad158
Advanced Data Structure
Algorithms
Dynamic Programming
Tree
Dynamic Programming
Tree
Algorithms
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Red-Black Tree | Set 2 (Insert)
Disjoint Set Data Structures
Ordered Set and GNU C++ PBDS
Insert Operation in B-Tree
Binary Indexed Tree or Fenwick Tree
SDE SHEET - A Complete Guide for SDE Preparation
Top 50 Array Coding Problems for Interviews
DSA Sheet by Love Babbar
Difference between BFS and DFS
A* Search Algorithm