Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Program to check there is any common reachable node in a graph or not in Python
Suppose we have an edge list of a directed graph with n nodes numbered from 0 to n-1. Given two integer values a and b, we need to check whether there exists a node c such that we can reach both a and b from c.
For a = 2 and b = 3, the output will be True because node c = 0 can reach both nodes 2 and 3.
Algorithm
We'll use Depth-First Search (DFS) to find all nodes reachable from both a and b in the reversed graph ?
- Convert edge list to adjacency list with reversed edges
- Perform DFS from node a to find all nodes that can reach a
- Perform DFS from node b to find all nodes that can reach b
- Check if there's any intersection between these two sets
Implementation
def edge_list_to_graph(edges):
# Find maximum node number to determine graph size
nodes = set()
for x, y in edges:
nodes.add(x)
nodes.add(y)
graph_size = len(nodes)
graph = [[] for _ in range(max(nodes) + 1)]
# Build reversed adjacency list (y -> x instead of x -> y)
for x, y in edges:
graph[y].append(x)
return graph
def dfs(graph, node, visited):
if node not in visited:
visited.add(node)
for neighbor in graph[node]:
dfs(graph, neighbor, visited)
def has_common_reachable_node(edges, a, b):
# Build reversed graph
graph = edge_list_to_graph(edges)
# Find all nodes that can reach 'a' and 'b'
reachable_to_a = set()
reachable_to_b = set()
dfs(graph, a, reachable_to_a)
dfs(graph, b, reachable_to_b)
# Check for intersection
common_nodes = reachable_to_a.intersection(reachable_to_b)
return len(common_nodes) > 0
# Example usage
edges = [(0, 4), (4, 3), (1, 2), (0, 1), (0, 2), (1, 1)]
a = 2
b = 3
result = has_common_reachable_node(edges, a, b)
print(f"Common reachable node exists: {result}")
# Show which nodes can reach both a and b
graph = edge_list_to_graph(edges)
reachable_to_a = set()
reachable_to_b = set()
dfs(graph, a, reachable_to_a)
dfs(graph, b, reachable_to_b)
common_nodes = reachable_to_a.intersection(reachable_to_b)
print(f"Common nodes: {sorted(common_nodes)}")
Common reachable node exists: True Common nodes: [0]
How It Works
The algorithm works by reversing the graph edges. In the original graph, if there's an edge from x to y, we create an edge from y to x. This allows us to find all nodes that can reach a given target node by performing DFS from that target.
For the example above:
- Nodes that can reach node 2: {0, 1, 2}
- Nodes that can reach node 3: {0, 3, 4}
- Intersection: {0}
Time and Space Complexity
Time Complexity: O(V + E) where V is the number of vertices and E is the number of edges, as we perform DFS twice.
Space Complexity: O(V + E) for storing the adjacency list and visited sets.
Conclusion
This solution efficiently finds common reachable nodes using DFS on a reversed graph. The key insight is reversing edges to find all nodes that can reach specific targets, then checking for intersections.
