Open In App

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

Last Updated : 16 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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 <bits/stdc++.h>
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<int> 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<pair<int, int> > friends,
    vector<pair<int, 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];
    }
 
    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<pair<int, int> > friends
        = { { 1, 2 }, { 2, 3 }, { 4, 5 }, { 6, 7 } };
    vector<pair<int, int> > 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<Integer>[] 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<int>[] v = new List<int>[ 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>();
    }
 
    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




<script>
 
// JavaScript program for the above approach
 
 
let N = 100001
 
let n;
let amt = new Array(N);
let dp = new Array(N), c = new Array(N);
let parent = new Array(N);
let sz = new Array(N);
let v = new Array(N).fill(0).map(() => []);
 
 
// Function to find the parent of each
// node in the graph
function find(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
function Union(a, b) {
    // Find the parents of a and b
    let p1 = find(a);
    let 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]) {
        let 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
function dfs(src, par) {
    dp[src] = c[src];
    let mx = 0;
 
    // Traverse the adjacency list
    // of the src node
    for (let x of 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
function maximumMoney(n, amt, friends, groups) {
    // Iterate over the range [1, N]
    for (let 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];
    }
 
    let p = friends.length;
 
    // Merging friends into groups
    for (let i = 0; i < p; ++i) {
 
        // Perform the union operation
        Union(friends[i][0],
            friends[i][1]);
    }
 
    let m = groups.length;
 
    // Finding the parent of group
    // in which member is present
    for (let i = 0; i < m; ++i) {
 
        // Find the parent p1 and p2
        let p1 = find(groups[i][0]);
        let 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].push(p2);
            v[p2].push(p1);
        }
    }
 
    // Starting dfs from node which
    // is the parent of group in
    // which 1 is present
    dfs(find(1), 0);
 
    let ans = 0;
 
    // Ans is the maximum money
    // collected by each group
    for (let i = 1; i <= n; i++) {
        ans = Math.max(ans, dp[find(i)]);
    }
 
    // Print the answer
    document.write(ans + "<br>");
}
 
 
 
// Driver Code
 
amt = [5, 2, 3, 6, 1, 9, 8];
n = amt.length;
 
let friends
    = [[1, 2], [2, 3], [4, 5], [6, 7]];
let groups
    = [[1, 4], [1, 6]];
maximumMoney(n, amt, friends, groups);
 
</script>


Output

27

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



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads