|
| 1 | +--- |
| 2 | +title: Bridges and Articulation Points |
| 3 | +tags: |
| 4 | + - Bridge |
| 5 | + - Articulation Point |
| 6 | + - Cut Vertex |
| 7 | + - Cut Edge |
| 8 | + - Graph |
| 9 | +--- |
| 10 | + |
| 11 | +## DFS Order |
| 12 | + |
| 13 | +**DFS order** is traversing all the nodes of a given graph by fixing the root node in the same way as in the DFS algorithm, but without revisiting a discovered node. An important observation here is that the edges and nodes we use will form a **tree** structure. This is because, for every node (**except the root**), we only arrive from another node, and for the **root** node, we do not arrive from any other node, thus forming a **tree** structure. |
| 14 | + |
| 15 | +```cpp |
| 16 | +void dfs(int node){ |
| 17 | + used[node] = true; |
| 18 | + for(auto it : g[node]) |
| 19 | + if(!used[it]) |
| 20 | + dfs(it); |
| 21 | +} |
| 22 | +``` |
| 23 | +
|
| 24 | +### Types of Edges |
| 25 | +
|
| 26 | +When traversing a graph using DFS order, several types of edges can be encountered. These edges will be very helpful in understanding some graph algorithms. |
| 27 | +
|
| 28 | +**Types of Edges:** |
| 29 | +- **Tree edge:** These are the main edges used while traversing the graph. |
| 30 | +- **Forward edge:** These edges lead to a node that has been visited before and is located in our own subtree. |
| 31 | +- **Back edge:** These edges lead to nodes that have been visited before but where the DFS process is not yet complete. |
| 32 | +- **Cross edge:** These edges lead to nodes that have been visited before and where the DFS process is already complete. |
| 33 | +
|
| 34 | +An important observation about these edges is that in an undirected graph, it is impossible to have a cross edge. This is because it is not possible for an edge emerging from a node where the DFS process is complete to remain unvisited. |
| 35 | +
|
| 36 | +<figure markdown="span" style="width: 36%"> |
| 37 | + |
| 38 | +<figcaption>Green-colored edges are tree edges. Edge (1,8) is a forward edge. Edge (6,4) is a back edge. Edge (5,4) is a cross edge.</figcaption> |
| 39 | +</figure> |
| 40 | +
|
| 41 | +## Bridge |
| 42 | +
|
| 43 | +In an **undirected** and **connected** graph, if removing an edge causes the graph to become disconnected, this edge is called a **bridge**. |
| 44 | +
|
| 45 | +### Finding Bridges |
| 46 | +
|
| 47 | +Although there are several algorithms to find bridges (such as **Chain Decomposition**), we will focus on **Tarjan's Algorithm**, which is among the easiest to implement and the fastest. |
| 48 | +
|
| 49 | +When traversing a graph using DFS, if there is a **back edge** coming out of the subtree of the lower endpoint of an edge, then that edge is **not** a bridge. This is because the **back edge** prevents the separation of the subtree and its ancestors when the edge is removed. |
| 50 | +
|
| 51 | +This algorithm is based exactly on this principle, keeping track of the minimum depth reached by the **back edge**s within the subtree of each node. |
| 52 | +
|
| 53 | +If the minimum depth reached by the **back edge**s in the subtree of the lower endpoint of an edge is greater than or equal to the depth of the upper endpoint, then this edge is a **bridge**. This is because no **back edge** in the subtree of the edge's lower endpoint reaches a node above the current edge. Therefore, if we remove this edge, the subtree and its ancestors become disconnected. |
| 54 | +
|
| 55 | +Using Tarjan's Algorithm, we can find all bridges in a graph with a time complexity of $\mathcal{O}(V + E)$, where $V$ represents the number of vertices and $E$ represents the number of edges in the graph. |
| 56 | +
|
| 57 | +```cpp |
| 58 | +int dfs(int node, int parent, int depth) { |
| 59 | + int minDepth = depth; |
| 60 | + dep[node] = depth; // dep dizisi her dugumun derinligini tutmaktadir. |
| 61 | + used[node] = true; |
| 62 | + for (auto it : g[node]) { |
| 63 | + if (it == parent) |
| 64 | + continue; |
| 65 | + if (used[it]) { |
| 66 | + minDepth = min(minDepth, dep[it]); |
| 67 | + // Eger komsu dugum daha once kullanilmis ise |
| 68 | + // Bu edge back edge veya forward edgedir. |
| 69 | + continue; |
| 70 | + } |
| 71 | + int val = dfs(it, node, depth + 1); |
| 72 | + // val degeri alt agacindan yukari cikan minimum derinliktir. |
| 73 | + if (val >= depth + 1) |
| 74 | + bridges.push_back({node, it}); |
| 75 | + minDepth = min(minDepth, val); |
| 76 | + } |
| 77 | + return minDepth; |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +## Articulation Point |
| 82 | + |
| 83 | +In an undirected graph, if removing a node increases the number of connected components, that node is called an **articulation point** or **cut point**. |
| 84 | + |
| 85 | +<figure markdown="span" style="width: 36%"> |
| 86 | + |
| 87 | +<figcaption>For example, if we remove node 0, the remaining nodes are split into two groups: 5 and 1, 2, 3, 4. Similarly, if we remove node 1, the nodes are split into 5, 0 and 2, 3, 4. Therefore, nodes 0 and 1 are **articulation points**.</figcaption> |
| 88 | +</figure> |
| 89 | + |
| 90 | +### Finding Articulation Points |
| 91 | + |
| 92 | +Tarjan's Algorithm for finding articulation points in an undirected graph: |
| 93 | + |
| 94 | +- Traverse the graph using DFS order. |
| 95 | + |
| 96 | +- For each node, calculate the depth of the minimum depth node that can be reached from the current node and its subtree through back edges. This value is called the **low** value of the node. |
| 97 | + |
| 98 | +- If the **low** value of any child of a non-root node is greater than or equal to the depth of the current node, then the current node is an **articulation point**. This is because no **back edge** in the subtree of this node can reach a node above the current node. Therefore, if this node is removed, its subtree will become disconnected from its ancestors. |
| 99 | + |
| 100 | +- If the current node is the root (the starting node of the DFS order) and there are multiple branches during the DFS traversal, then the root itself is an **articulation point**. This is because the root has multiple connected subgraphs. |
| 101 | + |
| 102 | +Using Tarjan's Algorithm, we can find all articulation points in a graph with a time complexity of $\mathcal{O}(V + E)$, where $V$ is the number of vertices and $E$ is the number of edges in the graph. |
| 103 | + |
| 104 | +```cpp |
| 105 | +int dfs(int node, int parent, int depth) { |
| 106 | + int minDepth = depth, children = 0; |
| 107 | + dep[node] = depth; // dep array holds depth of each node. |
| 108 | + used[node] = true; |
| 109 | + for (auto it : g[node]) { |
| 110 | + if (it == parent) |
| 111 | + continue; |
| 112 | + if (used[it]) { |
| 113 | + minDepth = min(minDepth, dep[it]); |
| 114 | + continue; |
| 115 | + } |
| 116 | + int val = dfs(it, node, depth + 1); |
| 117 | + if (val >= depth and parent != -1) |
| 118 | + isCutPoint[node] = true; |
| 119 | + minDepth = min(minDepth, val); |
| 120 | + children++; |
| 121 | + } |
| 122 | + // This if represents the root condition that we mentioned above. |
| 123 | + if (parent == -1 and children >= 2) |
| 124 | + isCutPoint[node] = true; |
| 125 | + return minDepth; |
| 126 | +} |
| 127 | +``` |
0 commit comments