From e9c28af6d0384f91c96c293ec3a1d05b6f61b0ea Mon Sep 17 00:00:00 2001 From: Rubal Singh Date: Tue, 6 Feb 2024 04:32:18 +0530 Subject: [PATCH] Add Kosaraju algorithm (#910) * added kosaraju's algorithm under /algorithms/graph * added test case for /algorithms/graph/strongly_connected_component_kosaraju --------- Co-authored-by: Rubal Singh --- .../strongly_connected_components_kosaraju.py | 81 +++++++++++++++++++ tests/test_graph.py | 17 ++++ 2 files changed, 98 insertions(+) create mode 100644 algorithms/graph/strongly_connected_components_kosaraju.py diff --git a/algorithms/graph/strongly_connected_components_kosaraju.py b/algorithms/graph/strongly_connected_components_kosaraju.py new file mode 100644 index 000000000..0c82a7af6 --- /dev/null +++ b/algorithms/graph/strongly_connected_components_kosaraju.py @@ -0,0 +1,81 @@ +""" +Implementing strongly connected components in a graph using Kosaraju's algorithm. +https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm +""" + + +class Kosaraju: + """ + Kosaraju's algorithm use depth first search approach to find strongly connected components in a directed graph. + Approach: + 1. Make a DFS call to keep track of finish time of each vertex. + 2. Tranpose the original graph. ie 1->2 transpose is 1<-2 + 3. Make another DFS call to calculate strongly connected components. + """ + + def dfs(self, i, V, adj, visited, stk): + visited[i] = 1 + + for x in adj[i]: + if visited[x] == -1: + self.dfs(x, V, adj, visited, stk) + + stk.append(i) + + def kosaraju(self, V, adj): + + stk, visited = [], [-1]*(V+1) + + for i in range(V): + if visited[i] == -1: + self.dfs(i, V, adj, visited, stk) + + stk.reverse() + res = stk.copy() + + ans, visited1 = 0, [-1]*(V+1) + + adj1 = [[] for x in range(V)] + + for i in range(len(adj)): + for x in adj[i]: + adj1[x].append(i) + + for i in range(len(res)): + if visited1[res[i]] == -1: + ans += 1 + self.dfs(res[i], V, adj1, visited1, stk) + + return ans + + +def main(): + """ + Let's look at the sample input. + + 6 7 #no of vertex, no of edges + 0 2 #directed edge 0->2 + 1 0 + 2 3 + 3 1 + 3 4 + 4 5 + 5 4 + + calculating no of strongly connected compnenets in a directed graph. + answer should be: 2 + 1st strong component: 0->2->3->1->0 + 2nd strongly connected component: 4->5->4 + """ + V, E = map(int, input().split()) + adj = [[] for x in range(V)] + + for i in range(E): + u, v = map(int, input().split()) + adj[u].append(v) + + print(Kosaraju().kosaraju(V, adj)) + + +if __name__ == '__main__': + main() diff --git a/tests/test_graph.py b/tests/test_graph.py index eb50dd4e1..540d29983 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -14,6 +14,7 @@ from algorithms.graph import cycle_detection from algorithms.graph import find_path from algorithms.graph import path_between_two_vertices_in_digraph +from algorithms.graph import strongly_connected_components_kosaraju import unittest @@ -349,3 +350,19 @@ def test_node_is_reachable(self): self.assertTrue(g.is_reachable(1, 3)) self.assertFalse(g.is_reachable(3, 1)) +class TestStronglyConnectedComponentsKosaraju(unittest.TestCase): + def test_kosaraju_algorithm(self): + V = 6 + adj = [ + [2], + [0], + [3], + [1, 4], + [5], + [4] + ] + + result = strongly_connected_components_kosaraju.Kosaraju().kosaraju(V, adj) + + # Expected result: 2 strongly connected components + self.assertEqual(result, 2)