GFG App
Open App
Browser
Continue

# Check if a cycle exists between nodes S and T in an Undirected Graph with only S and T repeating | Set – 2

Given an undirected graph with N nodes and two vertices S & T, the task is to check if a cycle between these two vertices exists (and return it) or not, such that no other node except S and T appears more than once in that cycle.

Examples:

Input: N = 7, edges[][] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 2}, {2, 6}, {6, 0}}, S = 0, T = 4

Output: No simple cycle from S to T exists
Explanation: No simple cycle from S to T exists,
because node 2 appears two times, in the only cycle that exists between 0 & 4

Input: N = 7,  edges[][] = {{0, 1}, {1, 2}, {1, 6}, {2, 3}, {3, 4}, {4, 5}, {5, 2}, {2, 6}, {6, 0}},, S = 0, T = 4

Output:  0->1->3->4->5->2->6->0
Explanation: The cycle doesn’t repeat any node (except 0)

Naive approach: The naive approach of the problem is discussed in Set-1 of this problem.

Efficient Approach: In the naive approach there is checking for all possible paths. The idea in this approach is similar to the Ford Fulkerson algorithm with Edmonds-Karp implementation, but with only 2 BFS. Follow the below steps to solve the problem

1. First, make a directed graph by duplicating each node (except S and T) in receiver and sender:
• If the original graph had the edge: {a, b}, the new graph will have {sender_a, receiver_b}
• The only node that points to a sender is his receiver, so the only edge that ends in sender_v is: {receiver_v, sender_v}
2. Run a BFS to find a path from S to T, and memorize the path back (using a predecessor array).
3. Invert the edges in the path found, this step is similar to the update of an augmenting path in Ford Fulkerson.
• While inverting memorize the flow from one node to another in the path
• So, if the previous node of cur is pred, then flow[cur] = pred
• Finally, memorize the last node (before the node t), let’s call it: first_node (because it’s the first node, after t, of the flow_path), first_node = flow[t]
4. Run a BFS again to find the second path, and memorize the path back (using a predecessor array).
5. Memorize the flow of the second path again:
• Only mark the flow if there wasn’t a previous flow in an opposite direction, this way two opposite flows will be discarded. Therefore, if flow[pred] == cur don’t do: flow[cur] = pred
• If the previous node of cur is pred in a path, then flow[cur] = pred
6. Finally, join the paths:
• Traverse both paths by the flow, one path starting in first_node and the other flow[t]
• As we have 2 paths from t to s, by reverting one of them we will have one path from s to t and another from t to s.
• Traverse one path from s to t, and the other from t to s.

All this work duplicating the graph and registering the flow is done to assure that the same node won’t be traversed twice.

Below is the implementation of the above approach:

## Java

 import java.util.*;   public class CycleBetweenVertices {           static int N;     static List[] graph;     static int[] parent;     static boolean[] visited;     static boolean foundCycle;     static List cycle;     static int S, T;           public static List findCycle(int n, int[][] edges, int s, int t) {         N = n;         graph = new List[N];         parent = new int[N];         visited = new boolean[N];         foundCycle = false;         cycle = new ArrayList<>();         S = s;         T = t;                   for (int i = 0; i < N; i++) {             graph[i] = new ArrayList<>();             parent[i] = -1;         }                   for (int[] edge : edges) {             int u = edge[0];             int v = edge[1];             graph[u].add(v);             graph[v].add(u);         }                   dfs(S, -1);                   if (!foundCycle) {             return new ArrayList<>();         }                   Collections.reverse(cycle);         return cycle;     }           public static boolean dfs(int u, int p) {         visited[u] = true;         parent[u] = p;                   for (int v : graph[u]) {             if (foundCycle) {                 return true;             }                           if (!visited[v]) {                 if (dfs(v, u)) {                     return true;                 }             } else if (v != p && (v == S || v == T)) {                 foundCycle = true;                 cycle.add(v);                 for (int i = u; i != v; i = parent[i]) {                     cycle.add(i);                 }                 cycle.add(v);                 return true;             }         }                   return false;     }           public static void main(String[] args) {         int n = 7;         int[][] edges = {{0, 1}, {1, 2}, {1, 6}, {2, 3}, {3, 4}, {4, 5}, {5, 2}, {2, 6}, {6, 0}};         int s = 0;         int t = 4;                   List cycle = findCycle(n, edges, s, t);                   if (cycle.isEmpty()) {             System.out.println("No cycle exists between " + s + " and " + t + ".");         } else {             System.out.print("Cycle between " + s + " and " + t + ": ");             for (int i = 0; i < cycle.size(); i++) {                 System.out.print(cycle.get(i));                 if (i < cycle.size() - 1) {                     System.out.print(" -> ");                 }             }             System.out.println();         }     } }   //This code is contributed by Akash Jha

## C++

 #include using namespace std;   int N; vector graph[10001]; int parent[10001]; bool visited[10001]; bool foundCycle; vector cycle; int S, T;   bool dfs(int u, int p);   vector findCycle(int n, vector>& edges, int s, int t) {     N = n;     foundCycle = false;     cycle.clear();     S = s;     T = t;       for (int i = 0; i < N; i++) {         graph[i].clear();         parent[i] = -1;         visited[i] = false;     }       for (auto edge : edges) {         int u = edge[0];         int v = edge[1];         graph[u].push_back(v);         graph[v].push_back(u);     }       dfs(S, -1);       if (!foundCycle) {         return vector();     }       reverse(cycle.begin(), cycle.end());     return cycle; }   bool dfs(int u, int p) {     visited[u] = true;     parent[u] = p;       for (auto v : graph[u]) {         if (foundCycle) {             return true;         }           if (!visited[v]) {             if (dfs(v, u)) {                 return true;             }         } else if (v != p && (v == S || v == T)) {             foundCycle = true;             cycle.push_back(v);             for (int i = u; i != v; i = parent[i]) {                 cycle.push_back(i);             }             cycle.push_back(v);             return true;         }     }       return false; }     int main() {     int n = 7;     vector> edges = {{0, 1}, {1, 2}, {1, 6}, {2, 3}, {3, 4}, {4, 5}, {5, 2}, {2, 6}, {6, 0}};     int s = 0;     int t = 4;       vector cycle = findCycle(n, edges, s, t);       if (cycle.empty()) {         cout << "No cycle exists between " << s << " and " << t << "." << endl;     } else {         cout << "Cycle between " << s << " and " << t << ": ";         for (int i = 0; i < cycle.size(); i++) {             cout << cycle[i];             if (i < cycle.size() - 1) {                 cout << " -> ";             }         }         cout << endl;     }     return 0; }   //This code is contributed by Akash Jha

## C#

 using System; using System.Collections.Generic; using System.Linq;   class Program {     static int N;     static List[] graph;     static int[] parent;     static bool[] visited;     static bool foundCycle;     static List cycle;     static int S, T;       static bool dfs(int u, int p) {         visited[u] = true;         parent[u] = p;           foreach (int v in graph[u]) {             if (foundCycle) {                 return true;             }               if (!visited[v]) {                 if (dfs(v, u)) {                     return true;                 }             } else if (v != p && (v == S || v == T)) {                 foundCycle = true;                 cycle.Add(v);                 for (int i = u; i != v; i = parent[i]) {                     cycle.Add(i);                 }                 cycle.Add(v);                 return true;             }         }           return false;     }       static List FindCycle(int n, int[][] edges, int s, int t) {         N = n;         foundCycle = false;         cycle = new List();         S = s;         T = t;           graph = new List[N];         parent = new int[N];         visited = new bool[N];           for (int i = 0; i < N; i++) {             graph[i] = new List();             parent[i] = -1;             visited[i] = false;         }           foreach (var edge in edges) {             int u = edge[0];             int v = edge[1];             graph[u].Add(v);             graph[v].Add(u);         }           dfs(S, -1);           if (!foundCycle) {             return new List();         }           cycle.Reverse();         return cycle;     }       static void Main(string[] args) {         int n = 7;         int[][] edges = new int[][] {             new int[] {0, 1},             new int[] {1, 2},             new int[] {1, 6},             new int[] {2, 3},             new int[] {3, 4},             new int[] {4, 5},             new int[] {5, 2},             new int[] {2, 6},             new int[] {6, 0},         };         int s = 0;         int t = 4;           List cycle = FindCycle(n, edges, s, t);           if (cycle.Count == 0) {             Console.WriteLine(\$"No cycle exists between {s} and {t}.");         } else {             Console.Write(\$"Cycle between {s} and {t}: ");             Console.WriteLine(string.Join(" -> ", cycle));         }     } } //This code is contributed by AKash Jha

## Javascript

 let N; let graph = new Array(10001).fill().map(() => []); let parent = new Array(10001).fill(-1); let visited = new Array(10001).fill(false); let foundCycle; let cycle; let S, T;   function findCycle(n, edges, s, t) {     N = n;     foundCycle = false;     cycle = [];     S = s;     T = t;       for (let i = 0; i < N; i++) {         graph[i].length = 0;         parent[i] = -1;         visited[i] = false;     }       for (let edge of edges) {         let u = edge[0];         let v = edge[1];         graph[u].push(v);         graph[v].push(u);     }       dfs(S, -1);       if (!foundCycle) {         return [];     }       cycle.reverse();     return cycle; }   function dfs(u, p) {     visited[u] = true;     parent[u] = p;       for (let v of graph[u]) {         if (foundCycle) {             return true;         }           if (!visited[v]) {             if (dfs(v, u)) {                 return true;             }         } else if (v !== p && (v === S || v === T)) {             foundCycle = true;             cycle.push(v);             for (let i = u; i !== v; i = parent[i]) {                 cycle.push(i);             }             cycle.push(v);             return true;         }     }       return false; }   let n = 7; let edges = [[0, 1], [1, 2], [1, 6], [2, 3], [3, 4], [4, 5], [5, 2], [2, 6], [6, 0]]; let s = 0; let t = 4;   let cycleResult = findCycle(n, edges, s, t);   if (cycleResult.length === 0) {     console.log("No cycle exists between " + s + " and " + t + "."); } else {     console.log("Cycle between " + s + " and " + t + ": ");     for (let i = 0; i < cycleResult.length; i++) {         console.log(cycleResult[i]);         if (i < cycleResult.length - 1) {             console.log(" -> ");         }     }     console.log(); } //This code is contributed by Akash Jha

Output

[0, 6, 2, 5, 4, 3, 1, 0]

Complexity Analysis: Given below are the complexity for each function

1. Create duplicate graph: O(V+E)
2. 2 BFS:  O(V+E)
3. 2 inversions (registering flow) : O(path size) <= O(V+E)
4. Recreate the paths from the flow array: O(path size) <= O(V+E)
5. Reverse one path:  O(path size) <= O(V+E)

Time Complexity: O(V+E)
Auxiliary Space: O(N*N), where N is the count of vertices in the graph.

My Personal Notes arrow_drop_up