Given a directed graph, check whether the graph contains a cycle or not. Your function should return true if the given graph contains at least one cycle, else return false.
The first line of input contains an integer T, the number of test cases.
The first line of each test case contains two single space-separated integers ‘V’, and ‘E’. ‘V’ represents the number of nodes and ‘E’ represents the number of edges in the graph.
From the second line onwards of each test case, the next 'E' lines will denote the edges of the graph where every edge is defined by two single space-separated integers 'A' and 'B', which signifies an edge from vertex 'A’ to vertex 'B'.
Output Format:
For each test case print "true" if a cycle exists, else "false".
1 <= T <= 10
1 <= V <= 10^3
0 <= E <= 10^3
0 <= A, B < V
Time Limit: 1 sec
2
4 4
0 1
1 2
2 3
3 0
3 3
1 0
1 2
0 2
true
false
In the first case,
From node 0 we can reach 0 again by following this sequence of nodes in the path: 0,1,2,3,0. As we can see in the image below.

In the second case,
There is no cycle in the given graph. As we can see in the image below.

2
3 2
0 1
0 2
3 3
1 1
0 2
1 2
false
true
Can you think of changing the directed tree to a cyclic directed graph by adding one edge?
To change a directed tree to a cyclic directed graph by adding one edge, we can choose a node that has more than zero ancestors and add an edge from that node to one of its ancestors. This can always form a complete cycle. This edge is called the back edge.
The basic idea is to traverse a graph using DFS and keep track of visited nodes and search for the back edge. If we found any back edge, we will return true, else we will return false.
DFS for a connected graph produces a tree. There is a cycle in a graph only if there is a back edge present in the graph. A back edge is an edge that is from a node to itself (self-loop) or one of its ancestors in the tree produced by DFS.
To detect a back edge, we can use coloring to keep track of visited nodes as well as ancestors. The color “0” represents an unvisited node. All the nodes with the color “1” represent the ancestor of the node. The color “2” represents visited nodes that are not ancestors of the node. We can traverse the graph using DFS and for each node, we check if there is any back edge that connects to its ancestor with color “1”. If we find any back edge then return true otherwise return false.
For a disconnected graph, we run the same algorithm of each connected graph and return true if there is a back edge in any of the connected graphs.
Algorithm:
O(V + E), Where ‘V’ is the number of nodes and E represents the number of edges in the given graph.
Since we are visiting each node and edge of the given graph only once. Therefore time complexity will be O(V + E).
O(V + E), Where ‘V’ is the number of nodes and E represents the number of edges in the given graph.
Since we are constructing an adjacency list and storing the color of each node in an array of size “N”. So the overall space complexity will be O(V + E).