Related Articles

# Minimize number of notes required to be distributed among students

• Difficulty Level : Basic
• Last Updated : 14 Sep, 2021

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:

1. Students named {“for”, “code”, “run”} require a single copy of notes, since there exists a mutual relationship between them.
2. Student named {“geeks”} requires a single copy of notes.
3. 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:

Below is the implementation of the above approach:

## C++

 `// C++ program for the above approach``#include ``using` `namespace` `std;` `// Structure of class Graph``class` `Graph {` `    ``// No. of vertices``    ``int` `V;` `    ``// An array of adjacency lists``    ``list<``int``>* adj;` `    ``// Function that fills the stack``    ``// with the vertices v``    ``void` `fillOrder(``int` `v, ``bool` `visited[],``                   ``stack<``int``>& Stack);` `    ``// Recursive function to perform``    ``// the DFS starting from v``    ``void` `DFSUtil(``int` `v, ``bool` `visited[]);` `public``:``    ``Graph(``int` `V);``    ``void` `addEdge(``int` `v, ``int` `w);` `    ``// Function to count the number of``    ``// strongly connected components``    ``void` `countSCCs();` `    ``// Function that returns reverse``    ``// (or transpose) of the graph``    ``Graph getTranspose();``};` `// Constructor of the Graph``Graph::Graph(``int` `V)``{``    ``this``->V = V;``    ``adj = ``new` `list<``int``>[V];``}` `// Recursive function to perform the``// DFS  starting from v``void` `Graph::DFSUtil(``int` `v, ``bool` `visited[])``{``    ``// Mark the current node as visited``    ``visited[v] = ``true``;` `    ``// Recurr for all the vertices``    ``// adjacent to this vertex``    ``list<``int``>::iterator i;` `    ``for` `(i = adj[v].begin();``         ``i != adj[v].end(); ++i) {``        ``if` `(!visited[*i])``            ``DFSUtil(*i, visited);``    ``}``}` `// Function to return the reverse``// (or transpose) of the graph``Graph Graph::getTranspose()``{``    ``Graph g(V);``    ``for` `(``int` `v = 0; v < V; v++) {` `        ``// Recurr for all the vertices``        ``// adjacent to this vertex``        ``list<``int``>::iterator i;` `        ``for` `(i = adj[v].begin();``             ``i != adj[v].end(); ++i) {``            ``g.adj[*i].push_back(v);``        ``}``    ``}``    ``return` `g;``}` `// Function to add an edge``void` `Graph::addEdge(``int` `v, ``int` `w)``{``    ``// Add w to v’s list``    ``adj[v].push_back(w);``}` `// Function to fill the stack with``// the vertices during DFS traversal``void` `Graph::fillOrder(``int` `v, ``bool` `visited[],``                      ``stack<``int``>& Stack)``{``    ``// Mark the current node as visited``    ``visited[v] = ``true``;` `    ``// Recurr for all the vertices``    ``// adjacent to this vertex``    ``list<``int``>::iterator i;` `    ``for` `(i = adj[v].begin();``         ``i != adj[v].end(); ++i) {``        ``if` `(!visited[*i])``            ``fillOrder(*i, visited, Stack);``    ``}` `    ``// All vertices reachable from``    ``// the node v are processed``    ``// Update the stack``    ``Stack.push(v);``}` `// Function that counts the strongly``// connected components in the graph``void` `Graph::countSCCs()``{``    ``stack<``int``> Stack;` `    ``// Mark all the vertices as not``    ``// visited (For first DFS)``    ``bool``* visited = ``new` `bool``[V];``    ``for` `(``int` `i = 0; i < V; i++)``        ``visited[i] = ``false``;` `    ``// Fill vertices in the stack``    ``// according to their finishing``    ``// time``    ``for` `(``int` `i = 0; i < V; i++) {``        ``// Vertex i is not visited``        ``if` `(visited[i] == ``false``)``            ``fillOrder(i, visited, Stack);``    ``}` `    ``// Create a reversed graph``    ``Graph gr = getTranspose();` `    ``// Mark all the vertices as``    ``// not visited (For second DFS)``    ``for` `(``int` `i = 0; i < V; i++)``        ``visited[i] = ``false``;``    ``int` `cnt = 0;` `    ``// Now process all vertices in``    ``// order defined by Stack``    ``while` `(Stack.empty() == ``false``) {` `        ``// Pop a vertex from stack``        ``int` `v = Stack.top();``        ``Stack.pop();` `        ``// Get the strongly connected``        ``// component of the popped``        ``// vertex``        ``if` `(visited[v] == ``false``) {` `            ``gr.DFSUtil(v, visited);``            ``cnt++;``        ``}``    ``}` `    ``// Print the result``    ``cout << cnt;``}` `// Function that counts the minimum``// number of notes required with the``// given criteria``void` `solve(vector& A,``           ``vector >& P)``{` `    ``Graph g(A.size());` `    ``// Used to map the strings to``    ``// their respective indices``    ``unordered_map um;``    ``for` `(``int` `i = 0; i < A.size(); i++) {``        ``um[A[i]] = i;``    ``}` `    ``// Iterate through all the edges``    ``// and add them to the graph``    ``for` `(``int` `i = 0; i < P.size(); i++) {``        ``int` `x = um[P[i][0]];``        ``int` `y = um[P[i][1]];``        ``g.addEdge(x, y);``    ``}` `    ``// Function Call``    ``g.countSCCs();``}` `// Driver Code``int` `main()``{` `    ``vector arr``        ``= { ``"geeks"``, ``"for"``, ``"code"``,``            ``"run"``, ``"compile"` `};``    ``vector > P = { { ``"geeks"``, ``"for"` `},``                                  ``{ ``"for"``, ``"code"` `},``                                  ``{ ``"code"``, ``"run"` `},``                                  ``{ ``"run"``, ``"compile"` `},``                                  ``{ ``"run"``, ``"for"` `} };` `    ``solve(arr, P);` `    ``return` `0;``}`

## Java

 `// Java program for above approach``import` `java.util.ArrayList;``import` `java.util.*;` `// Structure of class Graph``public` `class` `Graph{``    ` `// No. of vertices``int` `V;` `// An array of adjacency lists``ArrayList>  adj;` `// Constructor of the Graph``Graph(``int` `V)``{``    ``this``.V = V;``    ``adj = ``new` `ArrayList<>();``    ``for``(``int` `i = ``0``; i < V; i++)``    ``{``        ``adj.add(``new` `ArrayList<>());``    ``}``}` `// Recursive function to perform the``// DFS  starting from v``void` `DFSUtil(``int` `v, ``boolean` `visited[])``{``    ` `    ``// Mark the current node as visited``    ``visited[v] = ``true``;` `    ``// Recurr for all the vertices``    ``// adjacent to this vertex``    ``for``(``int` `i : adj.get(v))``    ``{``        ``if` `(!visited[i])``            ``DFSUtil(i, visited);``    ``}``}` `// Function to return the reverse``// (or transpose) of the graph``Graph getTranspose()``{``    ``Graph g = ``new` `Graph(V);``    ``for``(``int` `v = ``0``; v < V; v++)``    ``{``        ` `        ``// Recurr for all the vertices``        ``// adjacent to this vertex``        ``for``(``int` `i : adj.get(v))``        ``{``            ``g.adj.get(i).add(v);``        ``}``    ``}``    ``return` `g;``}` `// Function to add an edge``void` `addEdge(``int` `v, ``int` `w)``{``    ` `    ``// Add w to v’s list``    ``adj.get(v).add(w);``}` `// Function to fill the stack with``// the vertices during DFS traversal``void` `fillOrder(``int` `v, ``boolean``[] visited,``               ``Stack stack)``{``    ` `    ``// Mark the current node as visited``    ``visited[v] = ``true``;` `    ``// Recurr for all the vertices``    ``// adjacent to this vertex``    ``for``(``int` `i : adj.get(v))``    ``{``        ``if` `(!visited[i])``            ``fillOrder(i, visited, stack);``    ``}` `    ``// All vertices reachable from``    ``// the node v are processed``    ``// Update the stack``    ``stack.push(v);``}` `// Function that counts the strongly``// connected components in the graph``void` `countSCCs()``{``    ``Stack stack = ``new` `Stack<>();` `    ``// Mark all the vertices as not``    ``// visited (For first DFS)``    ``boolean``[] visited = ``new` `boolean``[V];``    ``for``(``int` `i = ``0``; i < V; i++)``        ``visited[i] = ``false``;` `    ``// Fill vertices in the stack``    ``// according to their finishing``    ``// time``    ``for``(``int` `i = ``0``; i < V; i++)``    ``{``        ` `        ``// Vertex i is not visited``        ``if` `(visited[i] == ``false``)``            ``fillOrder(i, visited, stack);``    ``}` `    ``// Create a reversed graph``    ``Graph gr = getTranspose();` `    ``// Mark all the vertices as``    ``// not visited (For second DFS)``    ``for``(``int` `i = ``0``; i < V; i++)``        ``visited[i] = ``false``;``        ` `    ``int` `cnt = ``0``;` `    ``// Now process all vertices in``    ``// order defined by Stack``    ``while` `(stack.empty() == ``false``)``    ``{``        ` `        ``// Pop a vertex from stack``        ``int` `v = stack.peek();``        ``stack.pop();` `        ``// Get the strongly connected``        ``// component of the popped``        ``// vertex``        ``if` `(visited[v] == ``false``)``        ``{``            ``gr.DFSUtil(v, visited);``            ``cnt++;``        ``}``    ``}` `    ``// Print the result``    ``System.out.print(cnt);``}` `// Function that counts the minimum``// number of notes required with the``// given criteria``static` `void` `solve(ArrayList A,``        ``ArrayList> P)``{``    ``Graph g = ``new` `Graph(A.size());` `    ``// Used to map the strings to``    ``// their respective indices``    ``HashMap um = ``new` `HashMap<>();``    ``for``(``int` `i = ``0``; i < A.size(); i++)``    ``{``        ``um.put(A.get(i), i);``    ``}` `    ``// Iterate through all the edges``    ``// and add them to the graph``    ``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);``    ``}` `    ``// Function Call``    ``g.countSCCs();``}` `// Driver code``public` `static` `void` `main(String[] args)``{``    ``ArrayList arr = ``new` `ArrayList<>();``    ``arr.add(``"geeks"``);``    ``arr.add(``"for"``);``    ``arr.add(``"code"``);``    ``arr.add(``"run"``);``    ``arr.add(``"compile"``);` `    ``ArrayList > 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);``}``}` `// This code is contributed by hritikrommie`
Output:
`3`

Time Complexity: O(N + M)
Auxiliary Space: O(N)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.

My Personal Notes arrow_drop_up