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++ 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 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 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# 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 |
<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)