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:
.png)
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:
.png)
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++
#include <bits/stdc++.h>
using namespace std;
class GFG {
public :
vector<vector<pair< int , int > > > adj;
vector< int > dp;
vector< int > vis;
int ans = 0;
void dfs( int curr_node, vector< int >& points)
{
vis[curr_node] = 1;
vector< int > child_nodes;
for ( auto x : adj[curr_node]) {
if (!vis[x.first]) {
dfs(x.first, points);
}
child_nodes.push_back(dp[x.first] - x.second);
}
sort(child_nodes.begin(), child_nodes.end(),
greater< int >());
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]);
}
ans = max(ans, max1 + max2 + points[curr_node]);
dp[curr_node] = max1 + points[curr_node];
}
int MaxPointPath( int n, vector< int > points,
vector<vector< int > > edges)
{
adj.resize(n + 1);
dp.resize(n + 1);
vis.resize(n + 1);
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] });
}
dfs(1, points);
return ans;
}
};
int main()
{
GFG obj;
int n = 5;
vector< int > points(n + 1);
points[1] = 6;
points[2] = 3;
points[3] = 2;
points[4] = 5;
points[5] = 0;
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 {
List<List<AbstractMap.SimpleEntry<Integer, Integer>>> adj;
List<Integer> dp;
List<Integer> vis;
int ans = 0 ;
GFG() {
adj = new ArrayList<>();
dp = new ArrayList<>();
vis = new ArrayList<>();
}
void dfs( int currNode, List<Integer> points) {
vis.set(currNode, 1 );
List<Integer> childNodes = new ArrayList<>();
for (AbstractMap.SimpleEntry<Integer, Integer> x : adj.get(currNode)) {
if (vis.get(x.getKey()) == 0 ) {
dfs(x.getKey(), points);
}
childNodes.add(dp.get(x.getKey()) - x.getValue());
}
Collections.sort(childNodes, Collections.reverseOrder());
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 ));
}
ans = Math.max(ans, max1 + max2 + points.get(currNode));
dp.set(currNode, max1 + points.get(currNode));
}
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 );
}
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 )));
}
dfs( 1 , points);
return ans;
}
public static void main(String[] args) {
GFG obj = new GFG();
int n = 5 ;
List<Integer> points = new ArrayList<>();
points.add( 0 );
points.add( 6 );
points.add( 3 );
points.add( 2 );
points.add( 5 );
points.add( 0 );
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
class GFG:
def __init__( self ):
self .adj = []
self .dp = []
self .vis = []
self .ans = 0
def dfs( self , curr_node, points):
self .vis[curr_node] = 1
child_nodes = []
for x in self .adj[curr_node]:
if not self .vis[x[ 0 ]]:
self .dfs(x[ 0 ], points)
child_nodes.append( self .dp[x[ 0 ]] - x[ 1 ])
child_nodes.sort(reverse = True )
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 ])
self .ans = max ( self .ans, max1 + max2 + points[curr_node])
self .dp[curr_node] = max1 + points[curr_node]
def MaxPointPath( self , n, points, edges):
self .adj = [[] for _ in range (n + 1 )]
self .dp = [ 0 ] * (n + 1 )
self .vis = [ 0 ] * (n + 1 )
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 ]))
self .dfs( 1 , points)
return self .ans
if __name__ = = "__main__" :
obj = GFG()
n = 5
points = [ 0 , 6 , 3 , 2 , 5 , 0 ]
edges = [
[ 1 , 2 , 10 ],
[ 2 , 3 , 3 ],
[ 2 , 4 , 1 ],
[ 1 , 5 , 11 ]
]
print (obj.MaxPointPath(n, points, edges))
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
class GFG
{
List<List<Tuple< int , int >>> adj = new List<List<Tuple< int , int >>>();
List< int > dp = new List< int >();
List< bool > vis = new List< bool >();
int ans = 0;
void dfs( int currNode, List< int > points)
{
vis[currNode] = true ;
List< int > childNodes = new List< int >();
foreach ( var edge in adj[currNode])
{
int childNode = edge.Item1;
int edgeLength = edge.Item2;
if (!vis[childNode])
{
dfs(childNode, points);
}
childNodes.Add(dp[childNode] - edgeLength);
}
childNodes.Sort((a, b) => b.CompareTo(a));
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]);
}
ans = Math.Max(ans, max1 + max2 + points[currNode]);
dp[currNode] = max1 + points[currNode];
}
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 );
}
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));
}
dfs(1, points);
return ans;
}
static void Main()
{
GFG obj = new GFG();
int n = 5;
List< int > points = new List< int >(n + 1)
{
0, 6, 3, 2, 5, 0
};
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
class GFG {
constructor() {
this .adj = [];
this .dp = [];
this .vis = [];
this .ans = 0;
}
dfs(currNode, points) {
this .vis[currNode] = 1;
const childNodes = [];
for (const [child, edgeLength] of this .adj[currNode]) {
if (! this .vis[child]) {
this .dfs(child, points);
}
childNodes.push( this .dp[child] - edgeLength);
}
childNodes.sort((a, b) => b - a);
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]);
}
this .ans = Math.max( this .ans, max1 + max2 + points[currNode]);
this .dp[currNode] = max1 + points[currNode];
}
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);
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]]);
}
this .dfs(1, points);
return this .ans;
}
}
const obj = new GFG();
const n = 5;
const points = [0, 6, 3, 2, 5, 0];
const edges = [
[1, 2, 10],
[2, 3, 3],
[2, 4, 1],
[1, 5, 11]
];
console.log(obj.MaxPointPath(n, points, edges));
|
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.
|