Given tree with N vertices rooted at node 0, edges given by array edges[][] and array arr[] of size N representing coins[] on each node. In one operation pick any node and collect all its coins. Task for this problem is to find maximum number of coins collected such that path sum from root node to any leaf node remains positive (path sum from root node to leaf node is total coins present on nodes of simple path between root to leaf).
Examples:
Input: N = 6, A[] = {5, 2, 5, 2, 1, 1 }, edges[][2] = {{0, 1}, {0, 2}, {0, 3}, {2, 4}, {4, 5}}
Output: 11
Explanation: We can collect coins from node 1, 2, 3, 4 and 5. Total coins = 2 + 5 + 2 + 1 + 1 = 11.
Since root node 0 is non zero any path starting from root node to any leaf will be non zero.Input: N = 7, A[] = { 20, 10, 9, 7, 4, 3, 5 }, edges[][2] = { {0, 1}, {0, 2}, {1, 3}, {1, 4}, {2, 5}, {2, 6} }
Output: 40
Explanation: We can collect coins from nodes 0, 2, 3 and 4. Total coins = 20 + 9 + 7 + 4 = 40
- path sum from 0 to 4 is equal to 10.
- path sum from 0 to 3 is equal to 10.
- path sum from 0 to 5 is equal to 3.
- path sum from 0 to 6 is equal to 5.
So, path sum from root node 0 to any leaf is non-zero.
Approach: To solve the problem, follow the below idea:
Observation: We have two choices to make for every subtree root. Either we pick the coins present on root of subtree or all coins on present on its descendants. Problem is turned into other way around lets find minimum coins required to keep path sum from root node to any leaf node non-zero.
Tree Dynamic Programming can be used to solve this problem. The main concept of DP in the problem will be:
DP[v] will store minimum coins required so path sum from node v to any leaf node is non-zero.
Transition: dp[v] = min(A[v], ∑dp[ui])
Step-by-step algorithm:
- Declaring Adjacency list adj[N] and fill the adjacency list by iterating on N – 1 edges.
- Declaring DP[] array of length N.
-
Declare dfs function which takes two parameters as input v node and p its parent.
- Iterate over all child’s u and find out dp[v] = ∑dp[ui]
- base case if v is not zero and there is only one element present in adjacent of v then update dp[v] as A[v]
- otherwise update dp[v] = min(dp[v], A[v])
- Call dfs(0, -1) function which is called for node 0 and its parent being -1
- Declare variable totalCoins which has sum of all coins present on every node of v
- Return totalCoins – dp[0]
Below is the implementation of the approach:
// C++ code to implement the approach #include <bits/stdc++.h> using namespace std;
// Function to Find maximum coins collected // from tree such that path sum from root node // to any leaf node is non zero int maxCoinsCollect( int N, int edges[][2], int A[])
{ // Declaring Adjacency List for tree
vector<vector< int > > adj(N);
// Filling Adjacency List
for ( int i = 0; i < N - 1; i++) {
adj[edges[i][0]].push_back(edges[i][1]);
adj[edges[i][1]].push_back(edges[i][0]);
}
// DP array initalized with zero
vector< int > dp(N, 0);
// dfs function
auto dfs = [&]( int v, int p, auto && dfs) -> void {
// iterating over child nodes
for ( auto & u : adj[v]) {
// if child of v is not equal to its parent
if (u != p) {
// call dfs function for child u
dfs(u, v, dfs);
// adding maximum coins chosen for child
// nodes
dp[v] += dp[u];
}
}
// base case
if (v != 0 and adj[v].size() == 1)
dp[v] = A[v];
else
// Either chose maximum coins by child nodes or
// coins present on root of the tree
dp[v] = min(dp[v], A[v]);
};
// calling dfs function
dfs(0, N, dfs);
// variable to store total coins
int totalCoins = accumulate(A, A + N, 0);
// returning final answer totalCoins - minimum
// coins required so that path sum from root to
// any leaf node is non zero
return totalCoins - dp[0];
} // Driver Code int main()
{ // Input
int N = 6;
int A[] = { 5, 2, 5, 2, 1, 1 };
int edges[][2] = {
{ 0, 1 }, { 0, 2 }, { 0, 3 }, { 2, 4 }, { 4, 5 }
};
// Function Call
cout << maxCoinsCollect(N, edges, A) << endl;
return 0;
} |
import java.util.ArrayList;
import java.util.List;
public class MaxCoinsCollect {
// Function to find maximum coins collected
// from the tree such that path sum from the
// root node to any leaf node is non zero
static int maxCoinsCollect( int N, List< int []> edges, int [] A) {
// Declaring Adjacency List for the tree
List<List<Integer>> adj = new ArrayList<>();
for ( int i = 0 ; i < N; i++) {
adj.add( new ArrayList<>());
}
// Filling Adjacency List
for ( int [] edge : edges) {
adj.get(edge[ 0 ]).add(edge[ 1 ]);
adj.get(edge[ 1 ]).add(edge[ 0 ]);
}
// DP array initialized with zero
int [] dp = new int [N];
// dfs function
dfs( 0 , - 1 , adj, dp, A);
// variable to store total coins
int totalCoins = 0 ;
for ( int coin : A) {
totalCoins += coin;
}
// returning final answer totalCoins - minimum
// coins required so that the path sum from root to
// any leaf node is non-zero
return totalCoins - dp[ 0 ];
}
// DFS function
static void dfs( int v, int p, List<List<Integer>> adj, int [] dp, int [] A) {
// iterating over child nodes
for ( int u : adj.get(v)) {
// if child of v is not equal to its parent
if (u != p) {
// call dfs function for child u
dfs(u, v, adj, dp, A);
// adding maximum coins chosen for child nodes
dp[v] += dp[u];
}
}
// base case
if (v != 0 && adj.get(v).size() == 1 ) {
dp[v] = A[v];
} else {
// Either choose maximum coins by child nodes or
// coins present on the root of the tree
dp[v] = Math.min(dp[v], A[v]);
}
}
// Driver Code
public static void main(String[] args) {
// Input
int N = 6 ;
int [] A = { 5 , 2 , 5 , 2 , 1 , 1 };
List< int []> edges = List.of(
new int []{ 0 , 1 }, new int []{ 0 , 2 },
new int []{ 0 , 3 }, new int []{ 2 , 4 }, new int []{ 4 , 5 }
);
// Function Call
System.out.println(maxCoinsCollect(N, edges, A));
}
} |
# Python code to implement the approach # Function to find maximum coins collected # from the tree such that path sum from the # root node to any leaf node is non zero def max_coins_collect(N, edges, A):
# Declaring Adjacency List for tree
adj = [[] for _ in range (N)]
# Filling Adjacency List
for edge in edges:
adj[edge[ 0 ]].append(edge[ 1 ])
adj[edge[ 1 ]].append(edge[ 0 ])
# DP array initialized with zero
dp = [ 0 ] * N
# dfs function
def dfs(v, p):
# iterating over child nodes
for u in adj[v]:
# if child of v is not equal to its parent
if u ! = p:
# call dfs function for child u
dfs(u, v)
# adding maximum coins chosen for child nodes
dp[v] + = dp[u]
# base case
if v ! = 0 and len (adj[v]) = = 1 :
dp[v] = A[v]
else :
# Either choose maximum coins by child nodes or
# coins present on the root of the tree
dp[v] = min (dp[v], A[v])
# calling dfs function
dfs( 0 , - 1 )
# variable to store total coins
total_coins = sum (A)
# returning final answer total_coins - minimum
# coins required so that path sum from root to
# any leaf node is non zero
return total_coins - dp[ 0 ]
# Driver Code if __name__ = = "__main__" :
# Input
N = 6
A = [ 5 , 2 , 5 , 2 , 1 , 1 ]
edges = [
[ 0 , 1 ], [ 0 , 2 ], [ 0 , 3 ], [ 2 , 4 ], [ 4 , 5 ]
]
# Function Call
print (max_coins_collect(N, edges, A))
|
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{ // Function to Find maximum coins collected
// from tree such that path sum from root node
// to any leaf node is non zero
static int MaxCoinsCollect( int N, int [,] edges, int [] A)
{
// Declaring Adjacency List for tree
var adj = new List<List< int >>(N);
for ( int i = 0; i < N; i++)
{
adj.Add( new List< int >());
}
// Filling Adjacency List
for ( int i = 0; i < N - 1; i++)
{
adj[edges[i, 0]].Add(edges[i, 1]);
adj[edges[i, 1]].Add(edges[i, 0]);
}
// DP array initialized with zero
var dp = new int [N];
// dfs function
Action< int , int > dfs = null ;
dfs = (v, p) =>
{
// iterating over child nodes
foreach ( var u in adj[v])
{
// if child of v is not equal to its parent
if (u != p)
{
// call dfs function for child u
dfs(u, v);
// adding maximum coins chosen for child nodes
dp[v] += dp[u];
}
}
// base case
if (v != 0 && adj[v].Count == 1)
dp[v] = A[v];
else
// Either chose maximum coins by child nodes or
// coins present on root of the tree
dp[v] = Math.Min(dp[v], A[v]);
};
// calling dfs function
dfs(0, N);
// variable to store total coins
int totalCoins = A.Sum();
// returning final answer totalCoins - minimum
// coins required so that path sum from root to
// any leaf node is non zero
return totalCoins - dp[0];
}
// Driver Code
static void Main( string [] args)
{
// Input
int N = 6;
int [] A = { 5, 2, 5, 2, 1, 1 };
int [,] edges = {
{ 0, 1 }, { 0, 2 }, { 0, 3 }, { 2, 4 }, { 4, 5 }
};
// Function Call
Console.WriteLine(MaxCoinsCollect(N, edges, A));
}
} |
// Function to find maximum coins collected // from the tree such that path sum from the // root node to any leaf node is non zero function maxCoinsCollect(N, edges, A) {
// Declaring Adjacency List for the tree
let adj = new Array(N).fill().map(() => []);
// Filling Adjacency List
for (let edge of edges) {
let [u, v] = edge;
adj[u].push(v);
adj[v].push(u);
}
// DP array initialized with zero
let dp = new Array(N).fill(0);
// dfs function
dfs(0, -1, adj, dp, A);
// variable to store total coins
let totalCoins = A.reduce((acc, coin) => acc + coin, 0);
// returning final answer totalCoins - minimum
// coins required so that the path sum from root to
// any leaf node is non-zero
return totalCoins - dp[0];
} // DFS function function dfs(v, p, adj, dp, A) {
// iterating over child nodes
for (let u of adj[v]) {
// if child of v is not equal to its parent
if (u !== p) {
// call dfs function for child u
dfs(u, v, adj, dp, A);
// adding maximum coins chosen for child nodes
dp[v] += dp[u];
}
}
// base case
if (v !== 0 && adj[v].length === 1) {
dp[v] = A[v];
} else {
// Either choose maximum coins by child nodes or
// coins present on the root of the tree
dp[v] = Math.min(dp[v], A[v]);
}
} // Driver Code ( function () {
// Input
let N = 6;
let A = [5, 2, 5, 2, 1, 1];
let edges = [
[0, 1], [0, 2],
[0, 3], [2, 4], [4, 5]
];
// Function Call
console.log(maxCoinsCollect(N, edges, A));
})(); |
11
Time Complexity: O(N), where N is the number of nodes in the tree.
Auxiliary Space: O(N)