Find any simple cycle in an undirected unweighted Graph
Given an un-directed and unweighted connected graph, find a simple cycle in that graph (if it exists).
Simple Cycle:
A simple cycle is a cycle in a Graph with no repeated vertices (except for the beginning and ending vertex).
Basically, if a cycle can’t be broken down to two or more cycles, then it is a simple cycle.
For better understanding, refer to the following image:
The graph in the above picture explains how the cycle 1 -> 2 -> 3 -> 4 -> 1 isn’t a simple cycle
because, it can be broken into 2 simple cycles 1 -> 3 -> 4 -> 1 and 1 -> 2 -> 3 -> 1.
Examples:
Input: edges[] = {(1, 2), (2, 3), (2, 4), (3, 4)}
Output: 2 => 3 => 4 => 2
Explanation:
This graph has only one cycle of length 3 which is a simple cycle.Input: edges[] = {(1, 2), (2, 3), (3, 4), (1, 4), (1, 3)}
Output: 1 => 3 => 4 => 1
Approach: The idea is to check that if the graph contains a cycle or not. This can be done by simply using a DFS.
Now, if the graph contains a cycle, we can get the end vertices (say a and b) of that cycle from the DFS itself. Now, if we run a BFS from a to b (ignoring the direct edge between a and b), we’ll be able to get the shortest path from a to b, which will give us the path of the shortest cycle containing the points a and b. The path can be easily tracked by using a parent array. This shortest cycle will be a simple cycle.
Proof that the shortest cycle will be a simple cycle:
We can prove this using contradiction. Let’s say there exists another simple cycle inside this cycle. This means the inner simple cycle will have a shorter length and, hence it can be said that there’s a shorter path from a to b. But we have found the shortest path from a to b using BFS. Hence, no shorter path exists and the found path is the shortest. So, no inner cycles can exist inside of the cycle we’ve found.
Hence, this cycle is a simple cycle.
Below is the implementation of the above approach:
C++
// C++ implementation to find the // simple cycle in the given path #include <bits/stdc++.h> using namespace std; #define MAXN 1005 // Declaration of the Graph vector<vector< int > > adj(MAXN); // Declaration of visited array vector< bool > vis(MAXN); int a, b; // Function to add edges // connecting 'a' and 'b' // to the graph void addedge( int a, int b) { adj[a].push_back(b); adj[b].push_back(a); } // Function to detect if the // graph contains a cycle or not bool detect_cycle( int node, int par) { // Marking the current node visited vis[node] = 1; // Traversing to the childs // of the current node // Simple DFS approach for ( auto child : adj[node]) { if (vis[child] == 0) { if (detect_cycle(child, node)) return true ; } // Checking for a back-edge else if (child != par) { // A cycle is detected // Marking the end-vertices // of the cycle a = child; b = node; return true ; } } return false ; } vector< int > simple_cycle; // Function to get the simple cycle from the // end-vertices of the cycle we found from DFS void find_simple_cycle( int a, int b) { // Parent array to get the path vector< int > par(MAXN, -1); // Queue for BFS queue< int > q; q.push(a); bool ok = true ; while (!q.empty()) { int node = q.front(); q.pop(); vis[node] = 1; for ( auto child : adj[node]) { if (node == a && child == b) // Ignoring the direct edge // between a and b continue ; if (vis[child] == 0) { // Updating the parent array par[child] = node; if (child == b) { // If b is reached, // we've found the // shortest path from // a to b already ok = false ; break ; } q.push(child); vis[child] = 1; } } // If required task is done if (ok == false ) break ; } // Cycle starting from a simple_cycle.push_back(a); int x = b; // Until we reach a again while (x != a) { simple_cycle.push_back(x); x = par[x]; } } // Driver Code int main() { // Creating the graph addedge(1, 2); addedge(2, 3); addedge(3, 4); addedge(4, 1); addedge(1, 3); if (detect_cycle(1, -1) == true ) { // If cycle is present // Resetting the visited array // for simple cycle finding vis = vector< bool >(MAXN, false ); find_simple_cycle(a, b); // Printing the simple cycle cout << "A simple cycle: " ; for ( auto & node : simple_cycle) { cout << node << " => " ; } cout << a; cout << "\n" ; } else { cout << "The Graph doesn't " << "contain a cycle.\n" ; } return 0; } |
Java
// Java implementation to // find the simple cycle // in the given path import java.util.*; class GFG{ static final int MAXN = 1005 ; // Declaration of the // Graph static Vector<Integer> []adj = new Vector[MAXN]; // Declaration of visited // array static boolean []vis = new boolean [MAXN]; static int a, b; // Function to add edges // connecting 'a' and 'b' // to the graph static void addedge( int a, int b) { adj[a].add(b); adj[b].add(a); } // Function to detect if the // graph contains a cycle or not static boolean detect_cycle( int node, int par) { // Marking the current // node visited vis[node] = true ; // Traversing to the childs // of the current node // Simple DFS approach for ( int child : adj[node]) { if (vis[child] == false ) { if (detect_cycle(child, node)) return true ; } // Checking for a back-edge else if (child != par) { // A cycle is detected // Marking the end-vertices // of the cycle a = child; b = node; return true ; } } return false ; } static Vector<Integer> simple_cycle = new Vector<>(); // Function to get the simple // cycle from the end-vertices //of the cycle we found from DFS static void find_simple_cycle( int a, int b) { // Parent array to get the path int []par = new int [MAXN]; // Queue for BFS Queue<Integer> q = new LinkedList<>(); q.add(a); boolean ok = true ; while (!q.isEmpty()) { int node = q.peek(); q.remove(); vis[node] = true ; for ( int child : adj[node]) { if (node == a && child == b) // Ignoring the direct edge // between a and b continue ; if (vis[child] == false ) { // Updating the parent // array par[child] = node; if (child == b) { // If b is reached, // we've found the // shortest path from // a to b already ok = false ; break ; } q.add(child); vis[child] = true ; } } // If required task // is done if (ok == false ) break ; } // Cycle starting from a simple_cycle.add(a); int x = b; // Until we reach // a again while (x != a) { simple_cycle.add(x); x = par[x]; } } // Driver Code public static void main(String[] args) { for ( int i = 0 ; i < adj.length; i++) adj[i] = new Vector<Integer>(); // Creating the graph addedge( 1 , 2 ); addedge( 2 , 3 ); addedge( 3 , 4 ); addedge( 4 , 1 ); addedge( 1 , 3 ); if (detect_cycle( 1 , - 1 ) == true ) { // If cycle is present // Resetting the visited array // for simple cycle finding Arrays.fill(vis, false ); find_simple_cycle(a, b); // Printing the simple cycle System.out.print( "A simple cycle: " ); for ( int node : simple_cycle) { System.out.print(node + " => " ); } System.out.print(a); System.out.print( "\n" ); } else { System.out.print( "The Graph doesn't " + "contain a cycle.\n" ); } } } // This code is contributed by shikhasingrajput |
Python3
# Python3 implementation to find the # simple cycle in the given path MAXN = 1005 # Declaration of the Graph adj = [[] for i in range (MAXN)] # Declaration of visited array vis = [ False for i in range (MAXN)] aa = 0 bb = 0 # Function to add edges # connecting 'a' and 'b' # to the graph def addedge(a, b): adj[a].append(b); adj[b].append(a); # Function to detect if the # graph contains a cycle or not def detect_cycle(node, par): global aa, bb # Marking the current node visited vis[node] = True ; # Traversing to the childs # of the current node # Simple DFS approach for child in adj[node]: if (vis[child] = = False ): if (detect_cycle(child, node)): return True ; # Checking for a back-edge elif (child ! = par): # A cycle is detected # Marking the end-vertices # of the cycle aa = child; bb = node; return True ; return False ; simple_cycle = [] # Function to get the simple cycle from the # end-vertices of the cycle we found from DFS def find_simple_cycle(a, b): # Parent array to get the path par = [ 0 for i in range (MAXN)] # Queue for BFS q = [] q.append(a); ok = True ; while ( len (q) ! = 0 ): node = q[ 0 ]; q.pop( 0 ); vis[node] = True ; for child in adj[node]: if (node = = a and child = = b): # Ignoring the direct edge # between a and b continue ; if (vis[child] = = False ): # Updating the parent array par[child] = node; if (child = = b): # If b is reached, # we've found the # shortest path from # a to b already ok = False ; break ; q.append(child); vis[child] = True ; # If required task is done if (ok = = False ): break ; # Cycle starting from a simple_cycle.append(a); x = b; # Until we reach a again while (x ! = a): simple_cycle.append(x); x = par[x]; # Driver Code if __name__ = = '__main__' : # Creating the graph addedge( 1 , 2 ); addedge( 2 , 3 ); addedge( 3 , 4 ); addedge( 4 , 1 ); addedge( 1 , 3 ); if (detect_cycle( 1 , - 1 ) = = True ): # If cycle is present # Resetting the visited array # for simple cycle finding for i in range (MAXN): vis[i] = False find_simple_cycle(aa, bb); # Printing the simple cycle print ( "A simple cycle: " , end = '') for node in simple_cycle: print (node, end = " => " ) print (aa) else : print ( "The Graph doesn't contain a cycle." ) # This code is contributed by rutvik_56 |
C#
// C# implementation to // find the simple cycle // in the given path using System; using System.Collections.Generic; class GFG{ static readonly int MAXN = 1005; // Declaration of the // Graph static List< int > []adj = new List< int >[MAXN]; // Declaration of visited // array static bool []vis = new bool [MAXN]; static int a, b; // Function to add edges // connecting 'a' and 'b' // to the graph static void addedge( int a, int b) { adj[a].Add(b); adj[b].Add(a); } // Function to detect if the // graph contains a cycle or not static bool detect_cycle( int node, int par) { // Marking the current // node visited vis[node] = true ; // Traversing to the childs // of the current node // Simple DFS approach foreach ( int child in adj[node]) { if (vis[child] == false ) { if (detect_cycle(child, node)) return true ; } // Checking for a back-edge else if (child != par) { // A cycle is detected // Marking the end-vertices // of the cycle a = child; b = node; return true ; } } return false ; } static List< int > simple_cycle = new List< int >(); // Function to get the simple // cycle from the end-vertices //of the cycle we found from DFS static void find_simple_cycle( int a, int b) { // Parent array to get the path int []par = new int [MAXN]; // Queue for BFS Queue< int > q = new Queue< int >(); q.Enqueue(a); bool ok = true ; while (q.Count != 0) { int node = q.Peek(); q.Dequeue(); vis[node] = true ; foreach ( int child in adj[node]) { if (node == a && child == b) // Ignoring the direct edge // between a and b continue ; if (vis[child] == false ) { // Updating the parent // array par[child] = node; if (child == b) { // If b is reached, // we've found the // shortest path from // a to b already ok = false ; break ; } q.Enqueue(child); vis[child] = true ; } } // If required task // is done if (ok == false ) break ; } // Cycle starting from a simple_cycle.Add(a); int x = b; // Until we reach // a again while (x != a) { simple_cycle.Add(x); x = par[x]; } } // Driver Code public static void Main(String[] args) { for ( int i = 0; i < adj.Length; i++) adj[i] = new List< int >(); // Creating the graph addedge(1, 2); addedge(2, 3); addedge(3, 4); addedge(4, 1); addedge(1, 3); if (detect_cycle(1, -1) == true ) { // If cycle is present // Resetting the visited array // for simple cycle finding for ( int i = 0; i < vis.Length; i++) vis[i] = false ; find_simple_cycle(a, b); // Printing the simple cycle Console.Write( "A simple cycle: " ); foreach ( int node in simple_cycle) { Console.Write(node + " => " ); } Console.Write(a); Console.Write( "\n" ); } else { Console.Write( "The Graph doesn't " + "contain a cycle.\n" ); } } } // This code is contributed by gauravrajput1 |
Javascript
<script> // Javascript implementation to // find the simple cycle // in the given path var MAXN = 1005; // Declaration of the // Graph var adj = Array.from(Array(MAXN), ()=>Array()); // Declaration of visited // array var vis = Array(MAXN).fill( false ); var a, b; // Function to add edges // connecting 'a' and 'b' // to the graph function addedge(a, b) { adj[a].push(b); adj[b].push(a); } // Function to detect if the // graph contains a cycle or not function detect_cycle(node, par) { // Marking the current // node visited vis[node] = true ; // Traversing to the childs // of the current node // Simple DFS approach for ( var child of adj[node]) { if (vis[child] == false ) { if (detect_cycle(child, node)) return true ; } // Checking for a back-edge else if (child != par) { // A cycle is detected // Marking the end-vertices // of the cycle a = child; b = node; return true ; } } return false ; } var simple_cycle = []; // Function to get the simple // cycle from the end-vertices //of the cycle we found from DFS function find_simple_cycle(a, b) { // Parent array to get the path var par = Array(MAXN); // Queue for BFS var q = []; q.push(a); var ok = true ; while (q.length != 0) { var node = q[0]; q.shift(); vis[node] = true ; for ( var child of adj[node]) { if (node == a && child == b) // Ignoring the direct edge // between a and b continue ; if (vis[child] == false ) { // Updating the parent // array par[child] = node; if (child == b) { // If b is reached, // we've found the // shortest path from // a to b already ok = false ; break ; } q.push(child); vis[child] = true ; } } // If required task // is done if (ok == false ) break ; } // Cycle starting from a simple_cycle.push(a); var x = b; // Until we reach // a again while (x != a) { simple_cycle.push(x); x = par[x]; } } // Driver Code // Creating the graph addedge(1, 2); addedge(2, 3); addedge(3, 4); addedge(4, 1); addedge(1, 3); if (detect_cycle(1, -1) == true ) { // If cycle is present // Resetting the visited array // for simple cycle finding for ( var i = 0; i < vis.length; i++) vis[i] = false ; find_simple_cycle(a, b); // Printing the simple cycle document.write( "A simple cycle: " ); for ( var node of simple_cycle) { document.write(node + " => " ); } document.write(a); document.write( "<br>" ); } else { document.write( "The Graph doesn't " + "contain a cycle.<br>" ); } </script> |
A simple cycle: 1 => 4 => 3 => 1
Time Complexity: O(V), where V is the number of vertices since we are doing just one DFS and BFS sequentially.
Auxiliary Space: O(MAXN)
Please Login to comment...