In graph theory, a Strongly Connected Component (SCC) is a subgraph of a directed graph in which there is a path between any two vertices, and vice versa. In other words, for every pair of vertices and within a SCC, there is a directed path from to and from to . SCCs play an important role in analyzing directed graphs, and algorithms for identifying them are widely used in problems like web page ranking, social network analysis, and dependency analysis.
A Strongly Connected Component (SCC) of a directed graph is a maximal subgraph in which any two vertices are mutually reachable. This means that there is a directed path from any vertex to any other vertex within the SCC, and vice versa.
Strongly connected components have a wide range of applications in various fields:
There are two main algorithms used to find the Strongly Connected Components (SCCs) of a directed graph:
Kosaraju’s algorithm for finding SCCs is based on two Depth-First Searches (DFS). It works in two main phases:
Steps of Kosaraju’s Algorithm:
Time Complexity: , where is the number of vertices and is the number of edges.
Example:
Consider the following directed graph:
A → B → C
↑ ↓
D ← E ← F
Tarjan’s algorithm is a more efficient algorithm that finds SCCs using a single DFS traversal. It uses low-link values to determine if a vertex is part of an SCC. The low-link value of a vertex is the smallest vertex that can be reached from that vertex, including itself.
Steps of Tarjan’s Algorithm:
Time Complexity: , where is the number of vertices and is the number of edges.
Example:
For the same directed graph:
A → B → C
↑ ↓
D ← E ← F
Tarjan’s algorithm will similarly identify two SCCs, and , in a single DFS traversal.
Below is an implementation of Kosaraju’s Algorithm to find SCCs in Python:
from collections import defaultdict
class Graph:
def __init__(self, vertices):
self.V = vertices
self.graph = defaultdict(list)
self.transposed_graph = defaultdict(list)
def add_edge(self, u, v):
self.graph[u].append(v)
self.transposed_graph[v].append(u)
def dfs(self, v, visited, stack):
visited[v] = True
for neighbor in self.graph[v]:
if not visited[neighbor]:
self.dfs(neighbor, visited, stack)
stack.append(v)
def dfs_transposed(self, v, visited):
visited[v] = True
print(v, end=" ")
for neighbor in self.transposed_graph[v]:
if not visited[neighbor]:
self.dfs_transposed(neighbor, visited)
def find_sccs(self):
stack = []
visited = [False] * self.V
# Step 1: Perform DFS and fill stack with vertices in the order of finishing times
for i in range(self.V):
if not visited[i]:
self.dfs(i, visited, stack)
# Step 2: Reverse the graph and perform DFS again
visited = [False] * self.V
print("Strongly Connected Components:")
while stack:
v = stack.pop()
if not visited[v]:
print("SCC: ", end="")
self.dfs_transposed(v, visited)
print()
# Example graph
g = Graph(6)
g.add_edge(0, 1)
g.add_edge(1, 2)
g.add_edge(2, 0)
g.add_edge(1, 3)
g.add_edge(3, 4)
g.add_edge(4, 5)
g.find_sccs()
Output:
Strongly Connected Components:
SCC: 0 2 1
SCC: 3
SCC: 4
SCC: 5