-
Notifications
You must be signed in to change notification settings - Fork 369
/
Copy pathTarjan.py
110 lines (85 loc) · 3.45 KB
/
Tarjan.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#'I will use Tarjan's Algorithm to find the bridges
# So, what is a bridge -> A bridge of a connected graph is a graph edge whose removal disconnects the graph
# So if we remove the bridge then the graph will be converted into multiple components.
#e.g. 1 ←-----→ 3 ←----→ 4
# ↑ ↗ ↑
# | ↗ |
# | ↗ |
# ↓ ↙ ↓
# 2 5
# In the above bidirectional graph, if we remove edge 3-4 then the graph will be broken into two different components so, we can say 3-4 is a bridge.
# T.c.=> O(V+E)
# Auxiliary Space: O(V)
from collections import defaultdict
class Graph:
def __init__(self, numNodes):
self.edges = []
self.numEdges = 0
self.adjList = defaultdict(list)
self.adjListSize = [0] * numNodes
self.tin = [-1] * numNodes
self.low = [-1] * numNodes
self.timer = 1
self.visited = [False] * numNodes
def addEdge(self, u, v):
self.edges.append((u, v))
self.numEdges += 1
self.adjList[u].append(v)
self.adjList[v].append(u)
self.adjListSize[u] += 1
self.adjListSize[v] += 1
def dfs(self, node, parent, dfsData, numBridges, bridges):
self.visited[node] = True
self.tin[node] = self.low[node] = self.timer
self.timer += 1
# Traverse all adjacent nodes of the current node
for child in self.adjList[node]:
# Skip the parent node to avoid going back in the same path
if child == parent:
continue
# If the child node is not visited, perform DFS on it
if not self.visited[child]:
# Store the DFS data of the child node
dfsData[child] = (child, node)
self.dfs(child, node, dfsData, numBridges, bridges)
# Update the low value of the current node based on the child's low value
self.low[node] = min(self.low[node], self.low[child])
# If the low value of the child is greater than the tin value of the current node,
# it means the edge is a bridge
if self.low[child] > self.tin[node]:
bridges[numBridges[0]] = (node, child)
numBridges[0] += 1
else:
# If the child node is already visited, update the low value of the current node
# based on the child's tin value
self.low[node] = min(self.low[node], self.tin[child])
def findBridges(self):
dfsData = {}
numBridges = [0]
bridges = [None] * self.numEdges
# Perform DFS on the graph starting from node 0
self.dfs(0, -1, dfsData, numBridges, bridges)
return bridges
if __name__ == '__main__':
numNodes = 5
graph = Graph(numNodes)
graph.addEdge(0, 1)
graph.addEdge(1, 3)
graph.addEdge(1, 2)
graph.addEdge(2, 4)
# 0 <--> 1 <---> 2
# | |
# ↑ ↑
# | |
# ↓ ↓
# 3 4
#
# In this graph there are 4 bridges [1,0] , [2,1] , [4,2] , [3,1]
#
# Assuming that the graph is bi-directional and connected.
#
#
bridges = graph.findBridges()
print(f"{len(bridges)} bridges found!")
for bridge in bridges:
print(f"{bridge[0]} --> {bridge[1]}")