GFG App
Open App
Browser
Continue

# Maximum money that can be collected among friends based on given conditions

Given an array arr[](1-based indexing) consisting of N positive integers such that arr[i] denotes the amount of the ith person. Also given are two 2D arrays say friends[][2] and groups[][2] such that each pair friends[i][0] and friends[i][1] are friends and form groups. Each pair groups[i][0] and groups[i][0] denotes the friends containing groups[i][0] and groups[i][1] can be friends among themselves.

The task is to find the maximum money that can be collected amongst themselves on the basis of the following conditions:

• If A and B are friends and B and C are friends then A and C are friends.
• If there can be a friendship between a group of people having A and a group of people having B and if there can be a friendship between a group of B and a group of C then there is a friendship between a group of A and a group of C.
• A set of friends forms the groups.

Examples:

Input: arr[] = {5, 2, 3, 6, 1, 9, 8}, friends[][] = {{1, 2}, {2, 3}, {4, 5}, {6, 7}}, groups[][] = {{1, 4}, {1, 6}}
Output: 27
Explanation:

Total Cost in Group 1 = 5 + 2 + 3 = 10.
Total Cost in Group 2 = 6 + 1 = 7.
Total Cost in Group 3 = 9 + 8 = 17.
As the group 1 can borrow money among both the group 2 and group 3. Therefore, the maximum money collected is 10 + 17 = 27.

Input: arr[] = {1, 2, 3, 4, 5, 6, 7}, friends[][] = {{1, 2}, {2, 3}, {4, 5}, {6, 7}}, groups[][] = {{1, 4}, {1, 6}}
Output: 19

Approach: The given problem can be solved by forming a group of friends and find the amount of money each group can have. The idea is to use Disjoint Set Union by making one of the group members a parent. Follow the below steps to solve the problem:

• While forming the group add the amount of each group of friends and store this amount with the parent of this group.
• Add an edge between different groups where two vertices of an edge show that these two groups can be friends of each other.
• Add an edge between the parent members of the group.
• Since, the parent stores the amount of money the corresponding group has, then the problem is reduced to find the maximum sum path from the node to the leaf where each node in the path represents the amount of money the group has.
• After completing the above steps, print the value of the maximum amount that can be collected.

Below is the implementation of the above approach:

## C++

 // C++ program for the above approach   #include using namespace std; #define N 100001   int n; int amt[N]; long long dp[N], c[N]; int parent[N]; long long sz[N]; vector v[N];   // Function to find the parent of each // node in the graph int find(int i) {     // If the parent is the same node     // itself     if (parent[i] == i)         return i;       // Recursively find the parent     return parent[i] = find(parent[i]); }   // Function to merge the friends of // each groups void Union(int a, int b) {     // Find the parents of a and b     int p1 = find(a);     int p2 = find(b);       // If the parents are the same     // then return     if (p1 == p2)         return;       // If the size of the parent p1     // is less than the p2, then     // swap the parents p1 and p2     if (sz[p1] < sz[p2]) {         swap(p1, p2);     }       parent[p2] = p1;     sz[p1] += sz[p2];       // Money in the group of p2 is     // added to the p1 and p2 is     // now the member of p1     c[p1] += c[p2];       // p2  is now the member of p1     c[p2] = 0; }   // Function to calculate the maximum // amount collected among friends void dfs(int src, int par) {     dp[src] = c[src];     long long mx = 0;       // Traverse the adjacency list     // of the src node     for (auto x : v[src]) {           if (x == par)             continue;           dfs(x, src);           // Calculate the maximum         // amount of the group         mx = max(mx, dp[x]);     }       // Adding the max amount of money     // with the current group     dp[src] += mx; }   // Function to find the maximum money // collected among friends void maximumMoney(     int n, int amt[],     vector > friends,     vector > groups) {     // Iterate over the range [1, N]     for (int i = 1; i <= n; i++) {           // Initialize the parent and         // the size of each node i         parent[i] = i;         sz[i] = 1;         c[i] = amt[i - 1];     }       int p = friends.size();       // Merging friends into groups     for (int i = 0; i < p; ++i) {           // Perform the union operation         Union(friends[i].first,               friends[i].second);     }       int m = groups.size();       // Finding the parent of group     // in which member is present     for (int i = 0; i < m; ++i) {           // Find the parent p1 and p2         int p1 = find(groups[i].first);         int p2 = find(groups[i].second);           // p1 and p2 are not in same         // group then add an edge         if (p1 != p2) {               // These two groups can be             // made friends. Hence,             // adding an edge             v[p1].push_back(p2);             v[p2].push_back(p1);         }     }       // Starting dfs from node which     // is the parent of group in     // which 1 is present     dfs(find(1), 0);       long long ans = 0;       // Ans is the maximum money     // collected by each group     for (int i = 1; i <= n; i++) {         ans = max(ans, dp[find(i)]);     }       // Print the answer     cout << ans << endl; }   // Driver Code signed main() {     int amt[] = { 5, 2, 3, 6,                   1, 9, 8 };     n = sizeof(amt) / sizeof(amt[0]);       vector > friends         = { { 1, 2 }, { 2, 3 }, { 4, 5 }, { 6, 7 } };     vector > groups         = { { 1, 4 }, { 1, 6 } };     maximumMoney(n, amt, friends, groups);       return 0; }

## Java

 // Java code to implement the approach import java.io.*; import java.lang.*; import java.util.*;   class GFG {     static int N = 100001;   static int[] amt = new int[N];   static int[] dp = new int[N];   static int[] c = new int[N];   static int[] parent = new int[N];   static int[] sz = new int[N];   static ArrayList[] v = new ArrayList[N];     // Function to find the parent of each   // node in the graph   static int find(int i)   {     // If the parent is the same node     // itself     if (parent[i] == i)       return i;     parent[i] = find(parent[i]);       // Recursively find the parent     return parent[i];   }     // Function to merge the friends of   // each groups   static void Union(int a, int b)   {     // Find the parents of a and b     int p1 = find(a);     int p2 = find(b);       // If the parents are the same     // then return     if (p1 == p2)       return;       // If the size of the parent p1     // is less than the p2, then     // swap the parents p1 and p2     if (sz[p1] < sz[p2]) {       int temp = p1;       p1 = p2;       p2 = temp;     }       parent[p2] = p1;     sz[p1] += sz[p2];       // Money in the group of p2 is     // added to the p1 and p2 is     // now the member of p1     c[p1] += c[p2];       // p2  is now the member of p1     c[p2] = 0;   }     // Function to calculate the maximum   // amount collected among friends   static void dfs(int src, int par)   {     dp[src] = c[src];     int mx = 0;       // Traverse the adjacency list     // of the src node     for (int x : v[src]) {       if (x == par)         continue;       dfs(x, src);         // Calculate the maximum       // amount of the group       mx = Math.max(mx, dp[x]);     }       // Adding the max amount of money     // with the current group     dp[src] += mx;   }     // Function to find the maximum money   // collected among friends   static void maximumMoney(int n, int[] amt,                            int[][] friends,                            int[][] groups)   {       // Iterate over the range [1, N]     for (int i = 1; i <= n; i++) {         // Initialize the parent and       // the size of each node i       parent[i] = i;       sz[i] = 1;       c[i] = amt[i - 1];       v[i] = new ArrayList<>();     }       int p = friends.length;       // Merging friends into groups     for (int i = 0; i < p; i++)         // Perform the union operation       Union(friends[i][0], friends[i][1]);       int m = groups.length;       // Finding the parent of group     // in which member is present     for (int i = 0; i < m; i++) {         // Find the parent p1 and p2       int p1 = find(groups[i][0]);       int p2 = find(groups[i][1]);         // p1 and p2 are not in same       // group then add an edge       if (p1 != p2) {           // These two groups can be         // made friends. Hence,         // adding an edge         v[p1].add(p2);         v[p2].add(p1);       }     }       // Starting dfs from node which     // is the parent of group in     // which 1 is present     dfs(find(1), 0);       int ans = 0;       // Ans is the maximum money     // collected by each group     for (int i = 1; i <= n; i++)       ans = Math.max(ans, dp[find(i)]);       // Print the answer     System.out.println(ans);   }   // Driver Function   public static void main(String[] args)     throws java.lang.Exception   {       // Inputs     int n = 7;     int[] amt = { 5, 2, 3, 6, 1, 9, 8 };     int[][] friends       = { { 1, 2 }, { 2, 3 }, { 4, 5 }, { 6, 7 } };     int[][] groups = { { 1, 4 }, { 1, 6 } };       // Function call     maximumMoney(n, amt, friends, groups);   } }

## Python3

 # Python3 program for the above approach N = 100001   amt = [0] * N dp = [0] * N c = [0] * N parent = [0] * N sz = [0] * N v = [[] for i in range(N)]   # Function to find the parent of each # node in the graph def find(i):           # If the parent is the same node     # itself     if (parent[i] == i):         return i       parent[i] = find(parent[i])     return parent[i]   # Function to merge the friends of # each groups def Union(a, b):           # Find the parents of a and b     p1 = find(a)     p2 = find(b)       # If the parents are the same     # then return     if (p1 == p2):         return       # If the size of the parent p1     # is less than the p2, then     # swap the parents p1 and p2     if (sz[p1] < sz[p2]):         temp = p1         p1 = p2         p2 = temp       parent[p2] = p1     sz[p1] += sz[p2]       # Money in the group of p2 is     # added to the p1 and p2 is     # now the member of p1     c[p1] += c[p2]       # p2  is now the member of p1     c[p2] = 0   # Function to calculate the maximum # amount collected among friends def dfs(src, par):           dp[src] = c[src]     mx = 0       # Traverse the adjacency list     # of the src node     for x in v[src]:         if (x == par):             continue           dfs(x, src)           # Calculate the maximum         # amount of the group         mx = max(mx, dp[x])       # Adding the max amount of money     # with the current group     dp[src] += mx   # Function to find the maximum money # collected among friends def maximumMoney(n, amt, friends, groups):           # Iterate over the range [1, N]     for i in range(1, n + 1):           # Initialize the parent and         # the size of each node i         parent[i] = i         sz[i] = 1         c[i] = amt[i - 1]       p = len(friends)       # Merging friends into groups     for i in range(p):           # Perform the union operation         Union(friends[i][0], friends[i][1])       m = len(groups)       # Finding the parent of group     # in which member is present     for i in range(m):           # Find the parent p1 and p2         p1 = find(groups[i][0])         p2 = find(groups[i][1])           # p1 and p2 are not in same         # group then add an edge         if (p1 != p2):               # These two groups can be             # made friends. Hence,             # adding an edge             v[p1].append(p2)             v[p2].append(p1)       # Starting dfs from node which     # is the parent of group in     # which 1 is present     dfs(find(1), 0)       ans = 0       # Ans is the maximum money     # collected by each group     for i in range(1, n + 1):         ans = max(ans, dp[find(i)])       # Print the answer     print(ans)   # Driver Code amt = [ 5, 2, 3, 6, 1, 9, 8 ] n = len(amt)   friends = [ [ 1, 2 ], [ 2, 3 ],             [ 4, 5 ], [ 6, 7 ] ] groups = [ [ 1, 4 ], [ 1, 6 ] ]   maximumMoney(n, amt, friends, groups)   # This code is contributed by _saurabh_jaiswal

## C#

 // C# code to implement the approach using System; using System.Collections.Generic; using System.Linq;   class GFG {   static int N = 100001;   static int[] amt = new int[N];   static int[] dp = new int[N];   static int[] c = new int[N];   static int[] parent = new int[N];   static int[] sz = new int[N];   static List[] v = new List[ N ];     // Function to find the parent of each   // node in the graph   static int Find(int i)   {       // If the parent is the same node     // itself     if (parent[i] == i)       return i;       parent[i] = Find(parent[i]);       // Recursively find the parent     return parent[i];   }     // Function to merge the friends of   // each groups   static void Union(int a, int b)   {       // Find the parents of a and b     int p1 = Find(a);     int p2 = Find(b);       // If the parents are the same     // then return     if (p1 == p2)       return;       // If the size of the parent p1     // is less than the p2, then     // swap the parents p1 and p2     if (sz[p1] < sz[p2]) {       int temp = p1;       p1 = p2;       p2 = temp;     }     parent[p2] = p1;     sz[p1] += sz[p2];       // Money in the group of p2 is     // added to the p1 and p2 is     // now the member of p1     c[p1] += c[p2];       // p2  is now the member of p1     c[p2] = 0;   }     // Function to calculate the maximum   // amount collected among friends   static void Dfs(int src, int par)   {     dp[src] = c[src];     int mx = 0;       // Traverse the adjacency list     // of the src node     foreach(int x in v[src])     {       if (x == par)         continue;       Dfs(x, src);         // Calculate the maximum       // amount of the group       mx = Math.Max(mx, dp[x]);     }       // Adding the max amount of money     // with the current group     dp[src] += mx;   }     // Function to find the maximum money   // collected among friends   static void MaximumMoney(int n, int[] amt,                            int[][] friends,                            int[][] groups)   {     // Iterate over the range [1, N]     for (int i = 1; i <= n; i++) {         // Initialize the parent and       // the size of each node i       parent[i] = i;       sz[i] = 1;       c[i] = amt[i - 1];       v[i] = new List();     }       int p = friends.Length;       // Merging friends into groups     for (int i = 0; i < p; i++)         // Perform the union operation       Union(friends[i][0], friends[i][1]);       int m = groups.Length;       // Finding the parent of group     // in which member is present     for (int i = 0; i < m; i++) {         // Find the parent p1 and p2       int p1 = Find(groups[i][0]);       int p2 = Find(groups[i][1]);         // p1 and p2 are not in same       // group then add an edge       if (p1 != p2) {           // These two groups can be         // made friends. Hence,         // adding an edge         v[p1].Add(p2);         v[p2].Add(p1);       }     }       // Starting dfs from node which     // is the parent of group in     // which 1 is present     Dfs(Find(1), 0);       int ans = 0;       // Ans is the maximum money     // collected by each group     for (int i = 1; i <= n; i++)       ans = Math.Max(ans, dp[Find(i)]);       // Print the answer     Console.WriteLine(ans);   }     // Driver Function   static void Main(string[] args)   {       // Inputs     int n = 7;     int[] amt = { 5, 2, 3, 6, 1, 9, 8 };     int[][] friends       = { new int[] { 1, 2 }, new int[] { 2, 3 },          new int[] { 4, 5 }, new int[] { 6, 7 } };     int[][] groups       = { new int[] { 1, 4 }, new int[] { 1, 6 } };       // Function call     MaximumMoney(n, amt, friends, groups);   } }   // This code is contributed by Prajwal Kandekar

## Javascript



Output

27

Time Complexity: O(N*log N)
Auxiliary Space: O(N)

My Personal Notes arrow_drop_up