Given an array arr[] consisting of N strings representing the name of the students in the class and another array of pairs P[][2] such that P[i][0] likes P[i][1], the task is to find the minimum number of notes to be distributed in the class such that sharing of notes can take place only if a student likes another student either directly or indirectly.
Examples:
Input: arr[] = {geeks, for, code, run, compile}, P[][] = {{geeks, for}, {for, code}, {code, run}, {run, compile}, {run, for}} Output: 3 Explanation: Below is the image to represent the relationship among the students:

From the above image:
- Students named {“for”, “code”, “run”} require a single copy of notes, since there exists a mutual relationship between them.
- Student named {“geeks”} requires a single copy of notes.
- Student named {“compile”} also require a single copy of notes.
So, the minimum number of notes required is 3.
Input: arr[] = {geeks, for, all, run, debug, compile}, P[][] = {{geeks, for}, {for, all}, {all, geeks}, {for, run}, {run, compile}, {compile, debug}, {debug, run}} Output: 2
Approach: The given problem can be solved by finding the number of strongly connected components in a directed graph after generating the relationship graph with the given conditions. Follow the steps below to solve the problem:
- Create a hashmap, say M to map the names of the students to their respective index values.
- Traverse the array A using the variable i and map each string A[i] in the map M to value i.
- Iterate all the pairs in the array P and for each pair get the corresponding values from the HashMap, M and create a directed edge between them.
- After traversing all the pairs, a directed graph is formed having N vertices and M number of edges.
- Create an empty stack S, and perform the DFS traversal of the graph:
- Create a recursive function that takes the index of a node and a visited array.
- Mark the current node as visited and traverse all the adjacent and unmarked nodes and call the recursive function with the index of the adjacent node.
- After traversing all the neighbors of the current node, push the current node in the stack S.
- Reverse directions of all edges to obtain the transpose of the constructed graph.
- Iterate until the stack S is not empty and perform the following steps:
- After completing the above steps, print the value of cnt as the result.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
class Graph {
int V;
list< int >* adj;
void fillOrder( int v, bool visited[],
stack< int >& Stack);
void DFSUtil( int v, bool visited[]);
public :
Graph( int V);
void addEdge( int v, int w);
void countSCCs();
Graph getTranspose();
};
Graph::Graph( int V)
{
this ->V = V;
adj = new list< int >[V];
}
void Graph::DFSUtil( int v, bool visited[])
{
visited[v] = true ;
list< int >::iterator i;
for (i = adj[v].begin();
i != adj[v].end(); ++i) {
if (!visited[*i])
DFSUtil(*i, visited);
}
}
Graph Graph::getTranspose()
{
Graph g(V);
for ( int v = 0; v < V; v++) {
list< int >::iterator i;
for (i = adj[v].begin();
i != adj[v].end(); ++i) {
g.adj[*i].push_back(v);
}
}
return g;
}
void Graph::addEdge( int v, int w)
{
adj[v].push_back(w);
}
void Graph::fillOrder( int v, bool visited[],
stack< int >& Stack)
{
visited[v] = true ;
list< int >::iterator i;
for (i = adj[v].begin();
i != adj[v].end(); ++i) {
if (!visited[*i])
fillOrder(*i, visited, Stack);
}
Stack.push(v);
}
void Graph::countSCCs()
{
stack< int > Stack;
bool * visited = new bool [V];
for ( int i = 0; i < V; i++)
visited[i] = false ;
for ( int i = 0; i < V; i++) {
if (visited[i] == false )
fillOrder(i, visited, Stack);
}
Graph gr = getTranspose();
for ( int i = 0; i < V; i++)
visited[i] = false ;
int cnt = 0;
while (Stack.empty() == false ) {
int v = Stack.top();
Stack.pop();
if (visited[v] == false ) {
gr.DFSUtil(v, visited);
cnt++;
}
}
cout << cnt;
}
void solve(vector<string>& A,
vector<vector<string> >& P)
{
Graph g(A.size());
unordered_map<string, int > um;
for ( int i = 0; i < A.size(); i++) {
um[A[i]] = i;
}
for ( int i = 0; i < P.size(); i++) {
int x = um[P[i][0]];
int y = um[P[i][1]];
g.addEdge(x, y);
}
g.countSCCs();
}
int main()
{
vector<string> arr
= { "geeks" , "for" , "code" ,
"run" , "compile" };
vector<vector<string> > P = { { "geeks" , "for" },
{ "for" , "code" },
{ "code" , "run" },
{ "run" , "compile" },
{ "run" , "for" } };
solve(arr, P);
return 0;
}
|
Java
import java.util.ArrayList;
import java.util.*;
public class Graph{
int V;
ArrayList<ArrayList<Integer>> adj;
Graph( int V)
{
this .V = V;
adj = new ArrayList<>();
for ( int i = 0 ; i < V; i++)
{
adj.add( new ArrayList<>());
}
}
void DFSUtil( int v, boolean visited[])
{
visited[v] = true ;
for ( int i : adj.get(v))
{
if (!visited[i])
DFSUtil(i, visited);
}
}
Graph getTranspose()
{
Graph g = new Graph(V);
for ( int v = 0 ; v < V; v++)
{
for ( int i : adj.get(v))
{
g.adj.get(i).add(v);
}
}
return g;
}
void addEdge( int v, int w)
{
adj.get(v).add(w);
}
void fillOrder( int v, boolean [] visited,
Stack<Integer> stack)
{
visited[v] = true ;
for ( int i : adj.get(v))
{
if (!visited[i])
fillOrder(i, visited, stack);
}
stack.push(v);
}
void countSCCs()
{
Stack<Integer> stack = new Stack<>();
boolean [] visited = new boolean [V];
for ( int i = 0 ; i < V; i++)
visited[i] = false ;
for ( int i = 0 ; i < V; i++)
{
if (visited[i] == false )
fillOrder(i, visited, stack);
}
Graph gr = getTranspose();
for ( int i = 0 ; i < V; i++)
visited[i] = false ;
int cnt = 0 ;
while (stack.empty() == false )
{
int v = stack.peek();
stack.pop();
if (visited[v] == false )
{
gr.DFSUtil(v, visited);
cnt++;
}
}
System.out.print(cnt);
}
static void solve(ArrayList<String> A,
ArrayList<ArrayList<String>> P)
{
Graph g = new Graph(A.size());
HashMap<String, Integer> um = new HashMap<>();
for ( int i = 0 ; i < A.size(); i++)
{
um.put(A.get(i), i);
}
for ( int i = 0 ; i < P.size(); i++)
{
int x = um.get(P.get(i).get( 0 ));
int y = um.get(P.get(i).get( 1 ));
g.addEdge(x, y);
}
g.countSCCs();
}
public static void main(String[] args)
{
ArrayList<String> arr = new ArrayList<>();
arr.add( "geeks" );
arr.add( "for" );
arr.add( "code" );
arr.add( "run" );
arr.add( "compile" );
ArrayList<ArrayList<String> > P = new ArrayList<>();
for ( int i = 0 ; i < 5 ; i++)
P.add( new ArrayList<>());
P.get( 0 ).add( "geeks" );
P.get( 0 ).add( "for" );
P.get( 1 ).add( "for" );
P.get( 1 ).add( "code" );
P.get( 2 ).add( "code" );
P.get( 2 ).add( "run" );
P.get( 3 ).add( "run" );
P.get( 3 ).add( "compile" );
P.get( 4 ).add( "run" );
P.get( 4 ).add( "for" );
solve(arr, P);
}
}
|
Python3
class Graph:
def __init__( self , V):
self .V = V
self .adj = [[] for i in range (V)]
def DFSUtil( self , v, visited):
visited[v] = True
for i in self .adj[v]:
if not visited[i]:
self .DFSUtil(i, visited)
def getTranspose( self ):
g = Graph( self .V)
for v in range ( self .V):
for i in self .adj[v]:
g.adj[i].append(v)
return g
def addEdge( self , v, w):
self .adj[v].append(w)
def fillOrder( self , v, visited, stack):
visited[v] = True
for i in self .adj[v]:
if not visited[i]:
self .fillOrder(i, visited, stack)
stack.append(v)
def countSCCs( self ):
stack = []
visited = [ False for i in range ( self .V)]
for i in range ( self .V):
if not visited[i]:
self .fillOrder(i, visited, stack)
gr = self .getTranspose()
visited = [ False for i in range ( self .V)]
cnt = 0
while stack:
v = stack.pop()
if not visited[v]:
gr.DFSUtil(v, visited)
cnt + = 1
return cnt
def solve(A, P):
um = {}
for i, a in enumerate (A):
um[a] = i
g = Graph( len (A))
for p in P:
x = um[p[ 0 ]]
y = um[p[ 1 ]]
g.addEdge(x, y)
print (g.countSCCs())
arr = [ "geeks" , "for" , "code" , "run" , "compile" ]
P = [
[ "geeks" , "for" ], [ "for" , "code" ],
[ "code" , "run" ], [ "run" , "compile" ],
[ "run" , "for" ]
]
solve(arr, P)
|
C#
using System;
using System.Collections.Generic;
public class Graph {
int V;
List<List< int > > adj;
public Graph( int V)
{
this .V = V;
adj = new List<List< int > >();
for ( int i = 0; i < V; i++) {
adj.Add( new List< int >());
}
}
void DFSUtil( int v, bool [] visited)
{
visited[v] = true ;
foreach ( int i in adj[v])
{
if (!visited[i]) {
DFSUtil(i, visited);
}
}
}
Graph GetTranspose()
{
Graph g = new Graph(V);
for ( int v = 0; v < V; v++) {
foreach ( int i in adj[v]) { g.adj[i].Add(v); }
}
return g;
}
void AddEdge( int v, int w) { adj[v].Add(w); }
void FillOrder( int v, bool [] visited, Stack< int > stack)
{
visited[v] = true ;
foreach ( int i in adj[v])
{
if (!visited[i]) {
FillOrder(i, visited, stack);
}
}
stack.Push(v);
}
void CountSCCs()
{
Stack< int > stack = new Stack< int >();
bool [] visited = new bool [V];
for ( int i = 0; i < V; i++) {
visited[i] = false ;
}
for ( int i = 0; i < V; i++) {
if (!visited[i]) {
FillOrder(i, visited, stack);
}
}
Graph gr = GetTranspose();
for ( int i = 0; i < V; i++) {
visited[i] = false ;
}
int cnt = 0;
while (stack.Count > 0) {
int v = stack.Peek();
stack.Pop();
if (!visited[v]) {
gr.DFSUtil(v, visited);
cnt++;
}
}
Console.WriteLine(cnt);
}
public static void Solve(List< string > A,
List<List< string > > P)
{
Graph g = new Graph(A.Count);
Dictionary< string , int > um
= new Dictionary< string , int >();
for ( int i = 0; i < A.Count; i++) {
um[A[i]] = i;
}
for ( int i = 0; i < P.Count; i++) {
int x = um[P[i][0]];
int y = um[P[i][1]];
g.AddEdge(x, y);
}
g.CountSCCs();
}
static void Main( string [] args)
{
List< string > A
= new List< string >{ "geeks" , "for" , "code" ,
"run" , "compile" };
List<List< string > > P = new List<List< string > >{
new List< string >{ "geeks" , "for" },
new List< string >{ "for" , "code" },
new List< string >{ "code" , "run" },
new List< string >{ "run" , "compile" },
new List< string >{ "run" , "for" },
};
Solve(A, P);
}
}
|
Javascript
const Graph =
function (V)
{
this .V = V;
this .adj = [];
for (let i = 0; i < V; i++) {
this .adj.push([]);
}
};
Graph.prototype.DFSUtil = function (v, visited)
{
visited[v] = true ;
for (let i of this .adj[v]) {
if (!visited[i]) {
this .DFSUtil(i, visited);
}
}
};
Graph.prototype.getTranspose = function ()
{
const g = new Graph( this .V);
for (let v = 0; v < this .V; v++) {
for (let i of this .adj[v]) {
g.adj[i].push(v);
}
}
return g;
};
Graph.prototype.addEdge = function (v, w)
{
this .adj[v].push(w);
};
Graph.prototype.fillOrder = function (v, visited, stack)
{
visited[v] = true ;
for (let i of this .adj[v]) {
if (!visited[i]) {
this .fillOrder(i, visited, stack);
}
}
stack.push(v);
};
Graph.prototype.countSCCs = function ()
{
const stack = [];
const visited = Array( this .V).fill( false );
for (let i = 0; i < this .V; i++) {
if (!visited[i]) {
this .fillOrder(i, visited, stack);
}
}
const gr = this .getTranspose();
visited.fill( false );
let cnt = 0;
while (stack.length > 0) {
const v = stack.pop();
if (!visited[v]) {
gr.DFSUtil(v, visited);
cnt++;
}
}
console.log(cnt);
};
const solve = function (A, P)
{
const um = new Map();
for (let i = 0; i < A.length; i++) {
um.set(A[i], i);
}
const g = new Graph(A.length);
for (let i = 0; i < P.length; i++) {
const x = um.get(P[i][0]);
const y = um.get(P[i][1]);
g.addEdge(x, y);
}
g.countSCCs();
};
let arr = [ "geeks" , "for" , "code" , "run" , "compile" ];
let P = [
[ "geeks" , "for" ], [ "for" , "code" ],
[ "code" , "run" ], [ "run" , "compile" ],
[ "run" , "for" ]
];
solve(arr, P);
|
Time Complexity: O(N + M) Auxiliary Space: O(N)
|