# 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[] such that P[i] likes P[i], 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]];` `        ``int` `y = um[P[i]];` `        ``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)

My Personal Notes arrow_drop_up
Recommended Articles
Page :