Open In App

The Earliest Moment When Everyone Become Friends

Improve
Improve
Like Article
Like
Save
Share
Report

Given a group of N people, each having a unique ID value from 0 to (N – 1) and an array arr[] of M elements of the form {U, V, time} representing that the person U will become acquainted with person V at the given time. Let’s say that person U is acquainted with person V if U is friends with V, or U is a friend of someone acquainted with V. The task is to find the earliest time at which every person became acquainted with each other.

Examples:

Input: N = 4, arr[] = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}
Output: 4
Explanation: Initially, the number of people are 4, i.e, {0}, {1}, {2}, {3}. 

  • At time = 2, {0} and {1} became friends. Therefore, the group of acquainted people becomes {0, 1}, {2}, {3}.
  • At time = 3, {1} and {2} became friends. Therefore, the group of acquainted people becomes {0, 1, 2}, {3}.
  • At time = 4, {2} and {3} became friends. Therefore, the group of acquainted people becomes {0, 1, 2, 3}.

Hence, at time = 4, every person became acquainted with each other.

Input: N = 6, arr[] = {{0, 1, 4}, {3, 4, 5}, {2, 3, 14}, {1, 5, 24}, {2, 4, 12}, {0, 3, 42}, {1, 2, 41}, {4, 5, 11}}
Output: 24

Approach: The given problem can be solved using the Disjoint Set Union Data Structure. The idea is to perform the union operations between people in order of the increasing value of time. The required answer will be the time when all people belong to the same set. Follow the steps below to solve the given problem:

  • Implement the Disjoint Set Union Data Structure with the union and findSet functions according to the algorithm discussed here.
  • Initialize a variable time, which stores the value of the current timestamp of the DSU.
  • Sort the given array arr[] in increasing order of time.
  • Traverse the given array arr[] using variable i, and perform union operation between (Ui, Vi) and update the current timestamp to timei if Ui and Vi belong to the different sets.
  • If the total number of sets after completely traversing through the array arr[] is 1, return the value of the variable time, else return -1.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include "bits/stdc++.h"
using namespace std;
 
// Implementation of DSU
class UnionFind {
 
    vector<int> parent, rank;
 
    // Stores the current timestamp
    int time;
 
    // Stores the count of current sets
    int count;
 
public:
    // Constructor to create and
    // initialize sets of N items
    UnionFind(int N)
        : parent(N), rank(N), count(N)
    {
        time = 0;
 
        // Creates N single item sets
        for (int i = 0; i < N; i++) {
            parent[i] = i;
            rank[i] = 1;
        }
    }
 
    // Function to find the set of
    // given item node
    int find(int node)
    {
        if (node == parent[node])
            return node;
        return parent[node]
               = find(parent[node]);
    }
 
    // Function to perform the union of
    // two sets represented by u and v,
    // and update the value of time
    void performUnion(int u, int v,
                      int updatedTime)
    {
 
        if (count == 1)
            return;
 
        // Find current sets of u and v
        int rootX = find(u);
        int rootY = find(v);
 
        if (rootX != rootY) {
 
            // Put smaller ranked item under
            // bigger ranked item if ranks
            // are different
            if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            }
            else if (rank[rootX] > rank[rootY]) {
                parent[rootY] = rootX;
            }
            else {
                parent[rootX] = rootY;
                rank[rootY] += 1;
            }
 
            // Update the value of the
            // current timestamp
            time = updatedTime;
 
            // Update the value of
            // set count
            count--;
        }
    }
 
    // Function to return current
    // set count
    int getCount() { return count; }
 
    // Function to return current
    // time stamp
    int getTime() { return time; }
};
 
// Comparator function to sort the array
// in increasing order of 3rd element
bool cmp(vector<int>& A, vector<int>& B)
{
    return A[2] <= B[2];
}
 
// Function to find the earliest time when
// everyone became friends to each other
int earliestTime(vector<vector<int> >& arr,
                 int N)
{
    // Sort array arr[] in increasing order
    sort(arr.begin(), arr.end(), cmp);
 
    // Initialize a DSU with N elements
    UnionFind unionFind(N);
 
    // Iterate over array arr[] perform
    // union operation for each element
    for (auto& it : arr) {
 
        // Perform union operation on
        // it[0] and it[1] and update
        // timestamp to it[2]
        unionFind.performUnion(
            it[0], it[1], it[2]);
    }
 
    // Return Answer
    if (unionFind.getCount() == 1) {
        return unionFind.getTime();
    }
    else {
        return -1;
    }
}
 
// Driver Code
int main()
{
    int N = 6;
    vector<vector<int> > arr
        = { { 0, 1, 4 }, { 3, 4, 5 },
            { 2, 3, 14 }, { 1, 5, 24 },
            { 2, 4, 12 }, { 0, 3, 42 },
            { 1, 2, 41 }, { 4, 5, 11 } };
 
    cout << earliestTime(arr, N);
 
    return 0;
}


Java




// Java program for the above approach
import java.util.*;
// Implementation of DSU
class UnionFind {
    private int[] parent;
    private int[] rank;
    private int time;
    private int count;
    // Constructor to create and
    // initialize sets of N items
    public UnionFind(int N)
    {
        parent = new int[N];
        rank = new int[N];
        time = 0;
        count = N;
        // Creates N single item sets
        for (int i = 0; i < N; i++) {
            parent[i] = i;
            rank[i] = 1;
        }
    }
    // Function to find the set of
    // given item node
    public int find(int node)
    {
        if (node == parent[node])
            return node;
        return parent[node] = find(parent[node]);
    }
    // Function to perform the union of
    // two sets represented by u and v,
    // and update the value of time
    public void performUnion(int u, int v, int updatedTime)
    {
        if (count == 1)
            return;
        // Find current sets of u and v
        int rootX = find(u);
        int rootY = find(v);
        // Put smaller ranked item under
        // bigger ranked item if ranks
        // are different
        if (rootX != rootY) {
            if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            }
            else if (rank[rootX] > rank[rootY]) {
                parent[rootY] = rootX;
            }
            else {
                parent[rootX] = rootY;
                rank[rootY] += 1;
            }
              // Update the value of the
            // current timestamp
            time = updatedTime;
           
              // Update the value of
            // set count
            count--;
        }
    }
    // Function to return current
    // set count
    public int getCount() { return count; }
   
    // Function to return current
    // time stamp
    public int getTime() { return time; }
}
 
class Main {
    private static int earliestTime(List<int[]> arr, int N)
    {
        arr.sort(Comparator.comparingInt(a -> a[2]));
 
        UnionFind unionFind = new UnionFind(N);
 
        for (int[] it : arr) {
            unionFind.performUnion(it[0], it[1], it[2]);
        }
 
        return unionFind.getCount() == 1
            ? unionFind.getTime()
            : -1;
    }
 
    public static void main(String[] args)
    {
        int N = 6;
        List<int[]> arr
            = Arrays.asList(new int[][] { { 0, 1, 4 },
                                          { 3, 4, 5 },
                                          { 2, 3, 14 },
                                          { 1, 5, 24 },
                                          { 2, 4, 12 },
                                          { 0, 3, 42 },
                                          { 1, 2, 41 },
                                          { 4, 5, 11 } });
 
        System.out.println(earliestTime(arr, N));
    }
}


Python3




# Python3 program for the above approach
 
# Class to implement Union Find algorithm
 
from typing import List
# Constructor to create and initialize sets of N items
class UnionFind:
 
    def __init__(self, N):
        self.parent = [i for i in range(N)]
        self.rank = [1 for i in range(N)]
        self.time = 0
        self.count = N
# Function to find the set of given item node
    def find(self, node):
        if node == self.parent[node]:
            return node
        self.parent[node] = self.find(self.parent[node])
        return self.parent[node]
# Function to perform the union of two sets
    # represented by u and v, and update the value of time
    def performUnion(self, u, v, updatedTime):
        if self.count == 1:
            return
 
        rootX = self.find(u)
        rootY = self.find(v)
 
        if rootX != rootY:
            if self.rank[rootX] < self.rank[rootY]:
                self.parent[rootX] = rootY
            elif self.rank[rootX] > self.rank[rootY]:
                self.parent[rootY] = rootX
            else:
                self.parent[rootX] = rootY
                self.rank[rootY] += 1
            self.time = updatedTime
            self.count -= 1
     
    def getCount(self):
        return self.count
     
    def getTime(self):
        return self.time
# Function to find the earliest time when everyone became friends to each other
def earliestTime(arr: List[List[int]], N: int) -> int:
    arr = sorted(arr, key=lambda x: x[2])
    unionFind = UnionFind(N)
    for it in arr:
        # Function to return current set count
        unionFind.performUnion(it[0], it[1], it[2])
    if unionFind.getCount() == 1:
      # Function to return current time stamp
        return unionFind.getTime()
    else:
        return -1
# Driver Code
if __name__ == "__main__":
    N = 6
    arr = [[0, 1, 4], [3, 4, 5],
           [2, 3, 14], [1, 5, 24],
           [2, 4, 12], [0, 3, 42],
           [1, 2, 41], [4, 5, 11]]
    print(earliestTime(arr, N))


Javascript




       // JavaScript code for the above approach
 
       // Implementation of DSU
       class UnionFind {
           constructor(N) {
               this.parent = new Array(N);
               this.rank = new Array(N);
               this.time = 0;
               this.count = N;
 
               // Creates N single item sets
               for (let i = 0; i < N; i++) {
                   this.parent[i] = i;
                   this.rank[i] = 1;
               }
           }
 
           // Function to find the set of
           // given item node
           find(node) {
               if (node === this.parent[node]) {
                   return node;
               }
               return (this.parent[node] = this.find(this.parent[node]));
           }
 
           // Function to perform the union of
           // two sets represented by u and v,
           // and update the value of time
           performUnion(u, v, updatedTime) {
               if (this.count === 1) {
                   return;
               }
 
               // Find current sets of u and v
               let rootX = this.find(u);
               let rootY = this.find(v);
 
               if (rootX !== rootY) {
                   // Put smaller ranked item under
                   // bigger ranked item if ranks
                   // are different
                   if (this.rank[rootX] < this.rank[rootY]) {
                       this.parent[rootX] = rootY;
                   } else if (this.rank[rootX] > this.rank[rootY]) {
                       this.parent[rootY] = rootX;
                   } else {
                       this.parent[rootX] = rootY;
                       this.rank[rootY] += 1;
                   }
 
                   // Update the value of the
                   // current timestamp
                   this.time = updatedTime;
 
                   // Update the value of
                   // set count
                   this.count--;
               }
           }
 
           // Function to return current
           // set count
           getCount() {
               return this.count;
           }
 
           // Function to return current
           // time stamp
           getTime() {
               return this.time;
           }
       }
 
       // Comparator function to sort the array
       // in increasing order of 3rd element
       function cmp(A, B) {
           return A[2] - B[2];
       }
 
       // Function to find the earliest time when
       // everyone became friends to each other
       function earliestTime(arr, N) {
           // Sort array arr[] in increasing order
           arr.sort(cmp);
 
           // Initialize a DSU with N elements
           let unionFind = new UnionFind(N);
 
           // Iterate over array arr[] perform
           // union operation for each element
           for (let it of arr) {
               // Perform union operation on
               // it[0] and it[1] and update
               // timestamp to it[2]
               unionFind.performUnion(it[0], it[1], it[2]);
           }
 
           // Return Answer
           if (unionFind.getCount() === 1) {
               return unionFind.getTime();
           } else {
               return -1;
           }
       }
       // Driver Code
 
       let N = 6;
       let arr = [
           [0, 1, 4],
           [3, 4, 5],
           [2, 3, 14],
           [1, 5, 24],
           [2, 4, 12],
           [0, 3, 42],
           [1, 2, 41],
           [4, 5, 11],
       ];
 
       console.log(earliestTime(arr, N));
 
// This code is contributed by Potta Lokesh.


C#




// C# program for the above approach
using System;
using System.Collections.Generic;
 
public class UnionFind
{
    private int[] parent;
    private int[] rank;
    private int time;
    private int count;
 
    // Constructor to create and
    // initialize sets of N items
    public UnionFind(int N)
    {
        parent = new int[N];
        rank = new int[N];
        time = 0;
        count = N;
 
        // Creates N single item sets
        for (int i = 0; i < N; i++)
        {
            parent[i] = i;
            rank[i] = 1;
        }
    }
 
    // Function to find the set of
    // given item node
    public int Find(int node)
    {
        if (node == parent[node])
        {
            return node;
        }
        return parent[node] = Find(parent[node]);
    }
 
    // Function to perform the union of
    // two sets represented by u and v,
    // and update the value of time
    public void PerformUnion(int u, int v, int updatedTime)
    {
        if (count == 1)
        {
            return;
        }
 
        // Find current sets of u and v
        int rootX = Find(u);
        int rootY = Find(v);
 
        // Put smaller ranked item under
        // bigger ranked item if ranks
        // are different
        if (rootX != rootY)
        {
            if (rank[rootX] < rank[rootY])
            {
                parent[rootX] = rootY;
            }
            else if (rank[rootX] > rank[rootY])
            {
                parent[rootY] = rootX;
            }
            else
            {
                parent[rootX] = rootY;
                rank[rootY] += 1;
            }
 
            // Update the value of the
            // current timestamp
            time = updatedTime;
 
            // Update the value of
            // set count
            count--;
        }
    }
 
    // Function to return current
    // set count
    public int GetCount() { return count; }
 
    // Function to return current
    // time stamp
    public int GetTime() { return time; }
}
 
class Program
{
      // Function to find the earliest time when
    // everyone became friends to each other
    private static int EarliestTime(List<int[]> arr, int N)
    {
          // Sort array arr[] in increasing order
        arr.Sort((a, b) => a[2].CompareTo(b[2]));
 
        UnionFind unionFind = new UnionFind(N);
 
          // Iterate over array arr[] perform
        // union operation for each element
        foreach (int[] it in arr)
        {
              // Perform union operation on
            // it[0] and it[1] and update
            // timestamp to it[2]
            unionFind.PerformUnion(it[0], it[1], it[2]);
        }
 
          // Return Answer
        return unionFind.GetCount() == 1
            ? unionFind.GetTime()
            : -1;
    }
 
      // Driver Code
    static void Main(string[] args)
    {
        int N = 6;
        List<int[]> arr = new List<int[]>
        {
            new int[] { 0, 1, 4 },
            new int[] { 3, 4, 5 },
            new int[] { 2, 3, 14 },
            new int[] { 1, 5, 24 },
            new int[] { 2, 4, 12 },
            new int[] { 0, 3, 42 },
            new int[] { 1, 2, 41 },
            new int[] { 4, 5, 11 }
        };
 
        Console.WriteLine(EarliestTime(arr, N));
    }
}
// This code is contributed by divyansh2212


Output: 

24

 

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



Last Updated : 24 Mar, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads