Open In App

Minimize Increments for Equal Path Sum from Root to Any Leaf

Last Updated : 21 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given arrays arr[] and edges[] where edges[i] denotes an undirected edge from edges[i][0] to edges[i][1] and arr[i] represents the value of the ith node. The task is to find the minimum number of increments by 1 required for any node, such that the sum of values along any path from the root to a leaf is equal.

Examples:

Input: N = 7, edges[] = {{0, 1}, {0, 2}, {1, 3}, {1, 4}, {2, 5}, {2, 6}}, A[] = {1, 5, 2, 2, 3, 3, 1}
Output: 6
Explanation:

tree1

  • 1st Operation: Increment A[3] by one, so A[3] becomes 3.
  • 2nd Operation: Increment A[6] by one, so A[6] becomes 3.
  • 3rd Operation: Increment A[6] by one, so A[6] becomes 4.
  • 4th Operation: Increment A[2] by one, so A[2] becomes 3.
  • 5th Operation: Increment A[2] by one, so A[2] becomes 4.
  • 6th Operation: Increment A[2] by one, so A[2] becomes 5.

In total of 6 operations all paths' sums from root node to leaf node becomes 9.

Input: N = 3, edges[] = {{0, 1}, {0, 2}}, A[] = {5, 3, 3}
Output: 0
Explanation: Sum of all paths from root to leaf are already equal. Therefore, no operations are required.

Approach: Implement the idea below to solve the problem:

The problem can be solved using DP on Trees. DP[i] will store the minimum cost for balancing subtree of ith node (balancing subtree means path sum from node V to all leaf nodes is same)

Let's say a node v has arr[v] = 5 and v has three child nodes u1, u2 and u3 with arr[u1] = 2, arr[u2] = 3 and arr[u3] = 5

  • path sum from root v to u1 is arr[v] + arr[u1] = 5 + 2 = 7
  • path sum from root v to u2 is arr[v] + arr[u2] = 5 + 3 = 8
  • path sum from root v to u3 is arr[v] + arr[u3] = 5 + 5 = 10

The intuition to solve this problem is to find the leaf node which is at maximum distance in this case it is u3 as distance arr[u3] = 5 and make all the other nodes equal to this node.

Increment node u1 and u2 to make it equal to 5. Currently arr[u1] = 2 and arr[u2] = 3, so perform increment operations 3 times on u1 to make arr[u1] = 5 and 2 times to make arr[u2] = 5. Now path sums are equal from v to u1, v to u2 and v to u3.

We will solve this problem for every subtree starting from leaf using Dynamic Programming and merging the answers of children with their parent.

Step-by-step algorithm:

  • Initialize DP[N] array with all values initially zero.
  • Create dfs() function that takes current node V and its parent P as input.
    • In dfs() function initialize maxi variable with value INT_MIN.
    • Iterate over all the child nodes of V and find maximum value arr[child] by updating maxi variable.
    • Iterate over all the child nodes again, this time perform operations to make all child's have equal path sum. It is done by DP transition: DP[V] = (DP[V] + DP[child] + maxi - arr[child])
    • Finally, as we move up in bottom-up manner from leaf to upper nodes distances increases which will be tracked by adding maxi value of child to arr[V].
  • Return DP[0] as the final answer.

Below is the implementation of the above approach:

C++
// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;

// dfs function
void dfs(int arr[], vector<int>& dp, int v, int parent,
         vector<vector<int> >& adj)
{
    // variable to find child with maximum value
    int maxi = INT_MIN;

    // iterating over adjacent elements to find maximum
    // node sum
    for (auto& u : adj[v]) {

        // if u is not parent call dfs for u
        if (u != parent) {

            // call dfs function
            dfs(arr, dp, u, v, adj);

            // updated maximum
            maxi = max(maxi, arr[u]);
        }
    }

    // iterating for performing operations to
    // make child nodes equal
    for (auto& u : adj[v]) {

        // if u is not parent call dfs for u
        if (u != parent) {
            // transition for dp
            dp[v] += dp[u] + maxi - arr[u];
        }
    }

    // going from child u to parent v path will  increase in
    // bottom up
    arr[v] = arr[v] + maxi;
}

// Function to Minimize Number of operations
// to make path sum from root to any leaf equal
int minimumCost(int N, int edges[][2], int arr[])
{
    // DP array initalized with 0
    vector<int> dp(N, 0);
    // Declaring adjacency List
    vector<vector<int> > adj(N + 1);

    // fill 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]);
    }

    // making dfs call from root 0
    dfs(arr, dp, 0, -1, adj);

    // Returing answer
    return dp[0];
}

// Driver Code
int32_t main()
{

    // Input
    int N = 7;
    int edges[][2] = { { 0, 1 }, { 0, 2 }, { 1, 3 },
                       { 1, 4 }, { 2, 5 }, { 2, 6 } };
    int arr[] = { 1, 5, 2, 2, 3, 3, 1 };

    // Function Call
    cout << minimumCost(N, edges, arr) << endl;

    return 0;
}
Java
import java.util.*;

class Main {
    // dfs function
    static void dfs(int[] arr, List<Integer> dp, int v,
                    int parent, List<List<Integer> > adj)
    {
        // variable to find child with maximum value
        int maxi = Integer.MIN_VALUE;

        // iterating over adjacent elements to find maximum
        // node sum
        for (int u : adj.get(v)) {
            // if u is not parent call dfs for u
            if (u != parent) {
                // call dfs function
                dfs(arr, dp, u, v, adj);
                // updated maximum
                maxi = Math.max(maxi, arr[u]);
            }
        }

        // iterating for performing operations to
        // make child nodes equal
        for (int u : adj.get(v)) {
            // if u is not parent call dfs for u
            if (u != parent) {
                // transition for dp
                dp.set(v, dp.get(v) + dp.get(u) + maxi
                              - arr[u]);
            }
        }

        // going from child u to parent v path will increase
        // in bottom up
        arr[v] = arr[v] + maxi;
    }

    // Function to Minimize Number of operations
    // to make path sum from root to any leaf equal
    static int minimumCost(int N, int[][] edges, int[] arr)
    {
        // DP array initialized with 0
        List<Integer> dp
            = new ArrayList<>(Collections.nCopies(N, 0));
        // Declaring adjacency List
        List<List<Integer> > adj = new ArrayList<>(N + 1);

        // initialize adjacency list
        for (int i = 0; i <= N; i++) {
            adj.add(new ArrayList<>());
        }

        // fill adjacency list
        for (int i = 0; i < N - 1; i++) {
            adj.get(edges[i][0]).add(edges[i][1]);
            adj.get(edges[i][1]).add(edges[i][0]);
        }

        // making dfs call from root 0
        dfs(arr, dp, 0, -1, adj);

        // Returning answer
        return dp.get(0);
    }

    // Driver Code
    public static void main(String[] args)
    {
        // Input
        int N = 7;
        int[][] edges = { { 0, 1 }, { 0, 2 }, { 1, 3 },
                          { 1, 4 }, { 2, 5 }, { 2, 6 } };
        int[] arr = { 1, 5, 2, 2, 3, 3, 1 };

        // Function Call
        System.out.println(minimumCost(N, edges, arr));
    }
}
Python3
def dfs(arr, dp, v, parent, adj):
    maxi = float('-inf')

    for u in adj[v]:
        if u != parent:
            dfs(arr, dp, u, v, adj)
            maxi = max(maxi, arr[u])

    for u in adj[v]:
        if u != parent:
            dp[v] += dp[u] + maxi - arr[u]

    # Check if any child node exists
    if maxi != float('-inf'):
        arr[v] = arr[v] + maxi

def minimum_cost(N, edges, arr):
    dp = [0] * N
    adj = [[] for _ in range(N + 1)]

    for edge in edges:
        adj[edge[0]].append(edge[1])
        adj[edge[1]].append(edge[0])

    dfs(arr, dp, 0, -1, adj)

    return dp[0]

# Driver Code
if __name__ == "__main__":
    N = 7
    edges = [[0, 1], [0, 2], [1, 3], [1, 4], [2, 5], [2, 6]]
    arr = [1, 5, 2, 2, 3, 3, 1]

    print(minimum_cost(N, edges, arr))

    
# This code is contributed by akshitaguprzj3
C#
using System;
using System.Collections.Generic;

class Program
{
    // dfs function
    static void DFS(int[] arr, List<int> dp, int v, int parent, List<List<int>> adj)
    {
        // variable to find child with maximum value
        int maxi = int.MinValue;

        // iterating over adjacent elements to find maximum
        // node sum
        foreach (var u in adj[v])
        {
            // if u is not parent call DFS for u
            if (u != parent)
            {
                // call DFS function
                DFS(arr, dp, u, v, adj);

                // updated maximum
                maxi = Math.Max(maxi, arr[u]);
            }
        }

        // iterating for performing operations to
        // make child nodes equal
        foreach (var u in adj[v])
        {
            // if u is not parent call DFS for u
            if (u != parent)
            {
                // transition for dp
                dp[v] += dp[u] + maxi - arr[u];
            }
        }

        // going from child u to parent v path will increase in
        // bottom up
        arr[v] = arr[v] + maxi;
    }

    // Function to Minimize Number of operations
    // to make path sum from root to any leaf equal
    static int MinimumCost(int N, int[,] edges, int[] arr)
    {
        // DP array initialized with 0
        List<int> dp = new List<int>(new int[N]);
        
        // Declaring adjacency List
        List<List<int>> adj = new List<List<int>>(N + 1);

        // fill adjacency list
        for (int i = 0; i <= N; i++)
        {
            adj.Add(new List<int>());
        }

        for (int i = 0; i < N - 1; i++)
        {
            adj[edges[i, 0]].Add(edges[i, 1]);
            adj[edges[i, 1]].Add(edges[i, 0]);
        }

        // making DFS call from root 0
        DFS(arr, dp, 0, -1, adj);

        // Returning answer
        return dp[0];
    }

    // Driver Code
    static void Main()
    {
        // Input
        int N = 7;
        int[,] edges = { { 0, 1 }, { 0, 2 }, { 1, 3 },
                         { 1, 4 }, { 2, 5 }, { 2, 6 } };
        int[] arr = { 1, 5, 2, 2, 3, 3, 1 };

        // Function Call
        Console.WriteLine(MinimumCost(N, edges, arr));
    }
}
JavaScript
// JavaScript code to implement the approach

// dfs function
function dfs(arr, dp, v, parent, adj) {
    // variable to find child with maximum value
    let maxi = -1e9;

    // iterating over adjacent elements to find maximum
    // node sum
    for (let u of adj[v]) {
        // if u is not parent call dfs for u
        if (u !== parent) {
            // call dfs function
            dfs(arr, dp, u, v, adj);

            // updated maximum
            maxi = Math.max(maxi, arr[u]);
        }
    }

    // iterating for performing operations to
    // make child nodes equal
    for (let u of adj[v]) {
        // if u is not parent call dfs for u
        if (u !== parent) {
            // transition for dp
            dp[v] += dp[u] + maxi - arr[u];
        }
    }

    // going from child u to parent v path will increase in
    // bottom up
    arr[v] = arr[v] + maxi;
}

// Function to Minimize Number of operations
// to make path sum from root to any leaf equal
function minimumCost(N, edges, arr) {
    // DP array initialized with 0
    let dp = new Array(N).fill(0);

    // Declaring adjacency List
    let adj = new Array(N + 1).fill(0).map(() => []);

    // fill adjacency list
    for (let i = 0; i < N - 1; i++) {
        adj[edges[i][0]].push(edges[i][1]);
        adj[edges[i][1]].push(edges[i][0]);
    }

    // making dfs call from root 0
    dfs(arr, dp, 0, -1, adj);

    // Returning answer
    return dp[0];
}

// Driver Code
function main() {
    // Input
    let N = 7;
    let edges = [[0, 1], [0, 2], [1, 3], [1, 4], [2, 5], [2, 6]];
    let arr = [1, 5, 2, 2, 3, 3, 1];

    // Function Call
    console.log(minimumCost(N, edges, arr));
}

// Run the driver code
main();

Output
6

Time Complexity: O(N), where N is the number of nodes in the tree.
Auxiliary Space: O(N)


Next Article

Similar Reads