Skip to content
geeksforgeeks
  • Tutorials
    • Python
    • Java
    • Data Structures & Algorithms
    • ML & Data Science
    • Interview Corner
    • Programming Languages
    • Web Development
    • CS Subjects
    • DevOps And Linux
    • School Learning
    • Practice Coding Problems
  • Courses
    • DSA to Development
    • Get IBM Certification
    • Newly Launched!
      • Master Django Framework
      • Become AWS Certified
    • For Working Professionals
      • Interview 101: DSA & System Design
      • Data Science Training Program
      • JAVA Backend Development (Live)
      • DevOps Engineering (LIVE)
      • Data Structures & Algorithms in Python
    • For Students
      • Placement Preparation Course
      • Data Science (Live)
      • Data Structure & Algorithm-Self Paced (C++/JAVA)
      • Master Competitive Programming (Live)
      • Full Stack Development with React & Node JS (Live)
    • Full Stack Development
    • Data Science Program
    • All Courses
  • DSA
  • Interview Problems on DP
  • Practice DP
  • MCQs on DP
  • Tutorial on Dynamic Programming
  • Optimal Substructure
  • Overlapping Subproblem
  • Memoization
  • Tabulation
  • Tabulation vs Memoization
  • 0/1 Knapsack
  • Unbounded Knapsack
  • Subset Sum
  • LCS
  • LIS
  • Coin Change
  • Word Break
  • Egg Dropping Puzzle
  • Matrix Chain Multiplication
  • Palindrome Partitioning
  • DP on Arrays
  • DP with Bitmasking
  • Digit DP
  • DP on Trees
  • DP on Graph
Open In App
Next Article:
Maximal Point Path
Next article icon

Maximal Point Path

Last Updated : 16 Oct, 2023
Comments
Improve
Suggest changes
Like Article
Like
Report

Given a tree with N nodes numbered from 1 to N. Each Node has a value denoting the number of points you get when you visit that Node. Each edge has a length and as soon as you travel through this edge number of points is reduced by the length of the edge, the task is to choose two nodes u and v such that the number of points is maximized at the end of the path from node u to node v.

Note: The number of points should not get negative in between the path from node u to node v.

Examples:

Input:

Treedrawio-(1)

Output: Maximal Point Path in this case will be 2->1->3 and maximum points at the end of path will be (3-2+1-2+3) = 3

Input:


Treedrawio-(2)

Output: Maximal Point Path in this case will be 2 -> 4 and maximum points at the end of path will be (3-1+5) = 7

Approach: This problem can be solved optimally using DP with trees concept.

Steps to solve the problem:

  • Root the tree at any node say (1).
  • For each of the nodes v in the tree, find the maximum points of the path passing through the node v. The answer will be the maximum of this value among all nodes in the tree.
  • To calculate this value for each node, maintain a dp array, where dp[v] is the maximal points of the path starting at node v for the subtree rooted at node v. dp[v] for a node v can be calculated from points[v] + max(dp[u] - wv->u ) where u is child of node v, wv->u is length of edge connecting node v and u and points[v] is the number points at the node v.
  • Now to find the maximum points of the path passing through the node v we calculate dp[u]-wv->u for each child of v and take the two biggest values from it and add points[v] in it.
  • If the maximum value of dp[u]-wv->u is negative then we will take 0 instead of it.

Below is the implementation of the above approach:

C++
// C++ code for the above approach: #include <bits/stdc++.h> using namespace std;  class GFG {  public:     // Adjacency list to store the edges.     vector<vector<pair<int, int> > > adj;      // To store maximum points of a path     // starting at a node     vector<int> dp;      // Visited vector to keep trackof nodes for     // which dp values has already been calculated     vector<int> vis;      // To store the final answer     int ans = 0;      // Function for visiting every node and     // calculating dp values for each node.     void dfs(int curr_node, vector<int>& points)     {          // Mark the current node as visited so         // that it does not have to be visited again.         vis[curr_node] = 1;          // To store maximum path starting         // at node minus lenght of edge connecting         // that node to current node for each         // child of current node.         vector<int> child_nodes;          // Iterating through each child         // of current node.         for (auto x : adj[curr_node]) {              // To check whether the child has been             // already visited or not             if (!vis[x.first]) {                  // Call dfs function for the child                 dfs(x.first, points);             }              // Push the value(maximum points path             // starting at this child node minus lenght             // of edge) into the vector             child_nodes.push_back(dp[x.first] - x.second);         }          // Sort the vector in decreasing order         // to pick 2 maximum 2 values.         sort(child_nodes.begin(), child_nodes.end(),              greater<int>());          // max1-to store maximum points path         // starting at child node of current         // node, max2-to store second maximum         // points path starting at child node         // of current node.         int max1 = 0, max2 = 0;         if (child_nodes.size() >= 2) {             max1 = max(max1, child_nodes[0]);             max2 = max(max2, child_nodes[1]);         }         else if (child_nodes.size() >= 1) {             max1 = max(max1, child_nodes[0]);         }          // Calculate maximum points path passing         // through current node.         ans = max(ans, max1 + max2 + points[curr_node]);          // Store maximum points path starting         // at current node in dp[curr_node]         dp[curr_node] = max1 + points[curr_node];     }      // To find maximal points path     int MaxPointPath(int n, vector<int> points,                      vector<vector<int> > edges)     {         adj.resize(n + 1);         dp.resize(n + 1);         vis.resize(n + 1);          // Filling adajency list         for (int i = 0; i < n - 1; i++) {             adj[edges[i][0]].push_back(                 { edges[i][1], edges[i][2] });             adj[edges[i][1]].push_back(                 { edges[i][0], edges[i][0] });         }          // Calling dfs for node 1         dfs(1, points);          return ans;     } };  // Driver code int main() {     GFG obj;      // Number of Vertices     int n = 5;      // Points at each node     vector<int> points(n + 1);     points[1] = 6;     points[2] = 3;     points[3] = 2;     points[4] = 5;     points[5] = 0;      // Edges and their lengths     vector<vector<int> > edges{         { 1, 2, 10 }, { 2, 3, 3 }, { 2, 4, 1 }, { 1, 5, 11 }     };      cout << obj.MaxPointPath(n, points, edges);     return 0; } 
Java
import java.util.*;  class GFG {     // Adjacency list to store the edges.     List<List<AbstractMap.SimpleEntry<Integer, Integer>>> adj;      // To store maximum points of a path starting at a node     List<Integer> dp;      // Visited vector to keep track of nodes for     // which dp values have already been calculated     List<Integer> vis;      // To store the final answer     int ans = 0;      // Constructor     GFG() {         adj = new ArrayList<>();         dp = new ArrayList<>();         vis = new ArrayList<>();     }      // Function for visiting every node and calculating dp values for each node.     void dfs(int currNode, List<Integer> points) {         // Mark the current node as visited so that it does not have to be visited again.         vis.set(currNode, 1);          // To store maximum path starting at node minus length of edge connecting that node to the current node for each child of the current node.         List<Integer> childNodes = new ArrayList<>();          // Iterating through each child of the current node.         for (AbstractMap.SimpleEntry<Integer, Integer> x : adj.get(currNode)) {             // To check whether the child has been already visited or not             if (vis.get(x.getKey()) == 0) {                 // Call dfs function for the child                 dfs(x.getKey(), points);             }              // Push the value (maximum points path starting at this child node minus length of the edge) into the vector             childNodes.add(dp.get(x.getKey()) - x.getValue());         }          // Sort the vector in decreasing order to pick 2 maximum 2 values.         Collections.sort(childNodes, Collections.reverseOrder());          // max1 - to store the maximum points path starting at the child node of the current node, max2 - to store the second maximum points path starting at the child node of the current node.         int max1 = 0, max2 = 0;         if (childNodes.size() >= 2) {             max1 = Math.max(max1, childNodes.get(0));             max2 = Math.max(max2, childNodes.get(1));         } else if (childNodes.size() == 1) {             max1 = Math.max(max1, childNodes.get(0));         }          // Calculate maximum points path passing through the current node.         ans = Math.max(ans, max1 + max2 + points.get(currNode));          // Store the maximum points path starting at the current node in dp[currNode]         dp.set(currNode, max1 + points.get(currNode));     }      // To find the maximal points path     int maxPointPath(int n, List<Integer> points, List<List<Integer>> edges) {         for (int i = 0; i <= n; i++) {             adj.add(new ArrayList<>());             dp.add(0);             vis.add(0);         }          // Filling the adjacency list         for (List<Integer> edge : edges) {             adj.get(edge.get(0)).add(new AbstractMap.SimpleEntry<>(edge.get(1), edge.get(2)));             adj.get(edge.get(1)).add(new AbstractMap.SimpleEntry<>(edge.get(0), edge.get(2)));         }          // Calling dfs for node 1         dfs(1, points);          return ans;     }      // Driver code     public static void main(String[] args) {         GFG obj = new GFG();          // Number of Vertices         int n = 5;          // Points at each node         List<Integer> points = new ArrayList<>();         points.add(0); // Adding an extra element at index 0 for simplicity         points.add(6);         points.add(3);         points.add(2);         points.add(5);         points.add(0);          // Edges and their lengths         List<List<Integer>> edges = Arrays.asList(                 Arrays.asList(1, 2, 10),                 Arrays.asList(2, 3, 3),                 Arrays.asList(2, 4, 1),                 Arrays.asList(1, 5, 11)         );          System.out.println(obj.maxPointPath(n, points, edges));     } } 
Python3
# Python Code Implementation class GFG:     def __init__(self):         # Adjacency list to store the edges.         self.adj = []          # To store maximum points of a path          #starting at a node         self.dp = []          # Visited vector to keep track of nodes          #for which dp values has already been calculated         self.vis = []          # To store the final answer         self.ans = 0      # Function for visiting every node and      #calculating dp values for each node.     def dfs(self, curr_node, points):         # Mark the current node as visited so          # that it does not have to be visited again.         self.vis[curr_node] = 1          # To store maximum path starting at node          # minus length of edge connecting that node to          # current node for each child of current node.         child_nodes = []          # Iterating through each child of current node.         for x in self.adj[curr_node]:                        # To check whether the child              # has been already visited or not             if not self.vis[x[0]]:                                # Call dfs function for the child                 self.dfs(x[0], points)              # Push the value(maximum points path              # starting at this child node minus length of edge)              # into the vector             child_nodes.append(self.dp[x[0]] - x[1])          # Sort the vector in decreasing          # order to pick 2 maximum values.         child_nodes.sort(reverse=True)          # max1-to store maximum points path starting          # at child node of current node, max2-to store          # second maximum points path starting at          # child node of current node.         max1 = 0         max2 = 0         if len(child_nodes) >= 2:             max1 = max(max1, child_nodes[0])             max2 = max(max2, child_nodes[1])         elif len(child_nodes) >= 1:             max1 = max(max1, child_nodes[0])          # Calculate maximum points path          # passing through current node.         self.ans = max(self.ans, max1 + max2 + points[curr_node])          # Store maximum points path starting          # at current node in dp[curr_node]         self.dp[curr_node] = max1 + points[curr_node]      # To find maximal points path     def MaxPointPath(self, n, points, edges):         self.adj = [[] for _ in range(n + 1)]         self.dp = [0] * (n + 1)         self.vis = [0] * (n + 1)          # Filling adjacency list         for i in range(n - 1):             self.adj[edges[i][0]].append((edges[i][1], edges[i][2]))             self.adj[edges[i][1]].append((edges[i][0], edges[i][2]))          # Calling dfs for node 1         self.dfs(1, points)          return self.ans   # Driver code if __name__ == "__main__":     obj = GFG()      # Number of Vertices     n = 5      # Points at each node     points = [0, 6, 3, 2, 5, 0]      # Edges and their lengths     edges = [         [1, 2, 10],         [2, 3, 3],         [2, 4, 1],         [1, 5, 11]     ]      print(obj.MaxPointPath(n, points, edges))  # This code is contributed by Sakshi 
C#
//C# code for the above approach using System; using System.Collections.Generic; using System.Linq;  class GFG {     // Adjacency list to store the edges.     List<List<Tuple<int, int>>> adj = new List<List<Tuple<int, int>>>();      // To store maximum points of a path     // starting at a node     List<int> dp = new List<int>();      // Visited vector to keep track of nodes for     // which dp values have already been calculated     List<bool> vis = new List<bool>();      // To store the final answer     int ans = 0;      // Function for visiting every node and     // calculating dp values for each node.     void dfs(int currNode, List<int> points)     {         // Mark the current node as visited so         // that it does not have to be visited again.         vis[currNode] = true;          // To store maximum path starting         // at node minus length of edge connecting         // that node to the current node for each         // child of the current node.         List<int> childNodes = new List<int>();          // Iterating through each child         // of the current node.         foreach (var edge in adj[currNode])         {             int childNode = edge.Item1;             int edgeLength = edge.Item2;              // To check whether the child has been             // already visited or not             if (!vis[childNode])             {                 // Call dfs function for the child                 dfs(childNode, points);             }              // Push the value (maximum points path             // starting at this child node minus length             // of edge) into the list             childNodes.Add(dp[childNode] - edgeLength);         }          // Sort the list in decreasing order         // to pick the maximum 2 values.         childNodes.Sort((a, b) => b.CompareTo(a));          // max1 - to store maximum points path         // starting at a child node of the current         // node, max2 - to store the second maximum         // points path starting at a child node         // of the current node.         int max1 = 0, max2 = 0;         if (childNodes.Count >= 2)         {             max1 = Math.Max(max1, childNodes[0]);             max2 = Math.Max(max2, childNodes[1]);         }         else if (childNodes.Count >= 1)         {             max1 = Math.Max(max1, childNodes[0]);         }          // Calculate maximum points path passing         // through the current node.         ans = Math.Max(ans, max1 + max2 + points[currNode]);          // Store the maximum points path starting         // at the current node in dp[currNode]         dp[currNode] = max1 + points[currNode];     }      // To find the maximal points path     int MaxPointPath(int n, List<int> points, List<List<int>> edges)     {         adj = new List<List<Tuple<int, int>>>(n + 1);         dp = new List<int>(n + 1);         vis = new List<bool>(n + 1);          for (int i = 0; i <= n; i++)         {             adj.Add(new List<Tuple<int, int>>());             dp.Add(0);             vis.Add(false);         }          // Filling adjacency list         foreach (var edge in edges)         {             int u = edge[0];             int v = edge[1];             int w = edge[2];             adj[u].Add(new Tuple<int, int>(v, w));             adj[v].Add(new Tuple<int, int>(u, w));         }          // Calling dfs for node 1         dfs(1, points);          return ans;     }      static void Main()     {         GFG obj = new GFG();          // Number of Vertices         int n = 5;          // Points at each node         List<int> points = new List<int>(n + 1)         {             0, 6, 3, 2, 5, 0         };          // Edges and their lengths         List<List<int>> edges = new List<List<int>>         {             new List<int> { 1, 2, 10 },             new List<int> { 2, 3, 3 },             new List<int> { 2, 4, 1 },             new List<int> { 1, 5, 11 }         };          Console.WriteLine(obj.MaxPointPath(n, points, edges));     } } 
JavaScript
// Javascript code for the above approach  class GFG {     constructor() {         // Adjacency list to store the edges.         this.adj = [];          // To store maximum points of a path         // starting at a node         this.dp = [];          // Visited vector to keep track of nodes for         // which dp values have already been calculated         this.vis = [];          // To store the final answer         this.ans = 0;     }      // Function for visiting every node and     // calculating dp values for each node.     dfs(currNode, points) {         // Mark the current node as visited so         // that it does not have to be visited again.         this.vis[currNode] = 1;          // To store maximum path starting         // at node minus length of edge connecting         // that node to the current node for each         // child of the current node.         const childNodes = [];          // Iterating through each child         // of the current node.         for (const [child, edgeLength] of this.adj[currNode]) {             // To check whether the child has been             // already visited or not             if (!this.vis[child]) {                 // Call dfs function for the child                 this.dfs(child, points);             }              // Push the value (maximum points path             // starting at this child node minus length             // of the edge) into the vector             childNodes.push(this.dp[child] - edgeLength);         }          // Sort the vector in decreasing order         // to pick 2 maximum values.         childNodes.sort((a, b) => b - a);          // max1 - to store maximum points path         // starting at the child node of the current         // node, max2 - to store second maximum         // points path starting at the child node         // of the current node.         let max1 = 0,             max2 = 0;         if (childNodes.length >= 2) {             max1 = Math.max(max1, childNodes[0]);             max2 = Math.max(max2, childNodes[1]);         } else if (childNodes.length >= 1) {             max1 = Math.max(max1, childNodes[0]);         }          // Calculate maximum points path passing         // through the current node.         this.ans = Math.max(this.ans, max1 + max2 + points[currNode]);          // Store maximum points path starting         // at the current node in dp[currNode]         this.dp[currNode] = max1 + points[currNode];     }      // To find maximal points path     MaxPointPath(n, points, edges) {         this.adj = Array(n + 1).fill().map(() => []);         this.dp = Array(n + 1).fill(0);         this.vis = Array(n + 1).fill(0);          // Filling adjacency list         for (let i = 0; i < n - 1; i++) {             this.adj[edges[i][0]].push([edges[i][1], edges[i][2]]);             this.adj[edges[i][1]].push([edges[i][0], edges[i][2]]);         }          // Calling dfs for node 1         this.dfs(1, points);          return this.ans;     } }  // Driver code const obj = new GFG();  // Number of Vertices const n = 5;  // Points at each node const points = [0, 6, 3, 2, 5, 0];  // Edges and their lengths const edges = [     [1, 2, 10],     [2, 3, 3],     [2, 4, 1],     [1, 5, 11] ];  console.log(obj.MaxPointPath(n, points, edges));  // This code is contributed by ragul21 

Output
7

Time Complexity: O(n*logn), since for each node sorting is performed on the values of its children.
Auxiliary Space : O(n), where n is the number of nodes in the tree.


Next Article
Maximal Point Path

M

mridul_gfg
Improve
Article Tags :
  • Tree
  • Dynamic Programming
  • DSA
  • Trees
  • Algorithms-Dynamic Programming
Practice Tags :
  • Dynamic Programming
  • Tree

Similar Reads

    DP on Trees for Competitive Programming
    Dynamic Programming (DP) on trees is a powerful algorithmic technique commonly used in competitive programming. It involves solving various tree-related problems by efficiently calculating and storing intermediate results to optimize time complexity. By using the tree structure, DP on trees allows p
    15+ min read
    Introduction to Dynamic Programming on Trees
    Dynamic Programming is a technique to solve problems by breaking them down into overlapping sub-problems which follows the optimal substructure. There are various problems using DP like subset sum, knapsack, coin change etc. DP can also be applied to trees to solve some specific problems.Given a bin
    13 min read
    DP on Trees | Set-3 ( Diameter of N-ary Tree )
    Given an N-ary tree, the task is to calculate the longest path between any two nodes (also known as the diameter of the tree).Examples: Example1: The diameter of the N-ary tree in the below example is 9, which represents the number of edges along the path marked with green nodes. Example2: The diame
    8 min read
    Maximum height of Tree when any Node can be considered as Root
    Given a tree with n nodes and n-1 edges, the task is to find the maximum height of the tree when any node in the tree is considered as the root of the tree. Example:Input: Output: 5Explanation: The below diagram represents a tree with 11 nodes and 10 edges and the path that gives us the maximum heig
    15+ min read
    Maximal Point Path
    Given a tree with N nodes numbered from 1 to N. Each Node has a value denoting the number of points you get when you visit that Node. Each edge has a length and as soon as you travel through this edge number of points is reduced by the length of the edge, the task is to choose two nodes u and v such
    14 min read
geeksforgeeks-footer-logo
Corporate & Communications Address:
A-143, 7th Floor, Sovereign Corporate Tower, Sector- 136, Noida, Uttar Pradesh (201305)
Registered Address:
K 061, Tower K, Gulshan Vivante Apartment, Sector 137, Noida, Gautam Buddh Nagar, Uttar Pradesh, 201305
GFG App on Play Store GFG App on App Store
Advertise with us
  • Company
  • About Us
  • Legal
  • Privacy Policy
  • In Media
  • Contact Us
  • Advertise with us
  • GFG Corporate Solution
  • Placement Training Program
  • Languages
  • Python
  • Java
  • C++
  • PHP
  • GoLang
  • SQL
  • R Language
  • Android Tutorial
  • Tutorials Archive
  • DSA
  • Data Structures
  • Algorithms
  • DSA for Beginners
  • Basic DSA Problems
  • DSA Roadmap
  • Top 100 DSA Interview Problems
  • DSA Roadmap by Sandeep Jain
  • All Cheat Sheets
  • Data Science & ML
  • Data Science With Python
  • Data Science For Beginner
  • Machine Learning
  • ML Maths
  • Data Visualisation
  • Pandas
  • NumPy
  • NLP
  • Deep Learning
  • Web Technologies
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • ReactJS
  • NextJS
  • Bootstrap
  • Web Design
  • Python Tutorial
  • Python Programming Examples
  • Python Projects
  • Python Tkinter
  • Python Web Scraping
  • OpenCV Tutorial
  • Python Interview Question
  • Django
  • Computer Science
  • Operating Systems
  • Computer Network
  • Database Management System
  • Software Engineering
  • Digital Logic Design
  • Engineering Maths
  • Software Development
  • Software Testing
  • DevOps
  • Git
  • Linux
  • AWS
  • Docker
  • Kubernetes
  • Azure
  • GCP
  • DevOps Roadmap
  • System Design
  • High Level Design
  • Low Level Design
  • UML Diagrams
  • Interview Guide
  • Design Patterns
  • OOAD
  • System Design Bootcamp
  • Interview Questions
  • Inteview Preparation
  • Competitive Programming
  • Top DS or Algo for CP
  • Company-Wise Recruitment Process
  • Company-Wise Preparation
  • Aptitude Preparation
  • Puzzles
  • School Subjects
  • Mathematics
  • Physics
  • Chemistry
  • Biology
  • Social Science
  • English Grammar
  • Commerce
  • World GK
  • GeeksforGeeks Videos
  • DSA
  • Python
  • Java
  • C++
  • Web Development
  • Data Science
  • CS Subjects
@GeeksforGeeks, Sanchhaya Education Private Limited, All rights reserved
We use cookies to ensure you have the best browsing experience on our website. By using our site, you acknowledge that you have read and understood our Cookie Policy & Privacy Policy
Lightbox
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
geeksforgeeks-suggest-icon
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.
geeksforgeeks-improvement-icon
Suggest Changes
min 4 words, max Words Limit:1000

Thank You!

Your suggestions are valuable to us.

What kind of Experience do you want to share?

Interview Experiences
Admission Experiences
Career Journeys
Work Experiences
Campus Experiences
Competitive Exam Experiences