Worked examples — Articulation points and bridges — Tarjan's low-link values
The scenario matrix
Before working examples, let us list every case class the topic can produce. Every worked example below is tagged with the cell(s) it covers.
| Cell | Structural situation | What we expect to find |
|---|---|---|
| A | A pure cycle (every edge on one loop) | 0 bridges, 0 articulation points |
| B | A pure path / chain (a line of nodes) | every edge a bridge, every internal node an AP |
| C | Root with children (star / hub) | root is AP, its edges may or may not be bridges |
| D | A subtree hanging off a cycle by ONE edge | that one edge is a bridge; the attach node is an AP |
| E | A back edge to itself (the tie) | NOT a bridge, but still an AP |
| F | Degenerate: single vertex, no edges | 0 of each — nothing to remove |
| G | Degenerate: two vertices, one edge | that edge is a bridge; neither vertex is an AP |
| H | Disconnected graph (two components) | each component analysed independently |
| I | Multi-edge (two parallel edges) trap | the naive v == parent skip lies |
| J | Word problem (real network) | translate → run → interpret |
| K | Exam twist (mixed graph, find both sets) | full trace, both answers |
We now cover all eleven cells with 9 examples. Watch the tags.
Example 1 — the pure cycle (cell A)
Forecast: Every node sits on one loop, so each has a "way around". Guess the counts before reading on — how many bridges? How many APs?

- Start DFS at 0, going as tree edges. Why this step? DFS explores as deep as it can first; that produces the chain ––– as the tree edges (black in the figure), leaving one leftover edge.
- Assign disc as we descend: . Initialise each (source 1). Why this step? must start at "I can at least reach myself" — the recurrence only ever lowers it from there.
- At node 3, the edge is a back edge (0 is a visited ancestor, and 0 is not 3's DFS parent). Apply source 3 of the recurrence: . Why this step? A back edge lets the whole loop "escape" all the way up to the discovery time of 0. This is the red arrow in the figure — the shortcut rope.
- Unwind low values up the chain (source 2): ; ; . Why this step? Each parent inherits the lowest reach of its child's subtree.
- Bridge test on each tree edge : need .
- : ? No ( false).
- : ? No. : ? No. Zero bridges.
- AP test: root 0 has only one tree child (node 1) → not an AP by the root rule. For non-root we need some child with ; but every and every with equality only at node 0 (a child of nobody). Check node 1: child 2 has ? false. Zero APs.
Verify: Physically remove any one edge, say : the loop becomes the path , still one connected piece. Remove any one vertex, say 1: survives connected. Matches 0 and 0. ✓
Example 2 — the pure chain (cell B, and cell G inside it)
Forecast: No loops at all. Cut any edge and the line snaps into two. Remove any middle node and the line snaps. Guess: how many bridges, how many APs?

- DFS from 0 produces exactly the chain as tree edges; there are no back edges because there is no loop. Why this step? Without a cycle there is no ancestor to jump back to, so every stays equal to its own .
- disc = low = for nodes . Why this step? Source 3 (back edge) never fires; source 2 only copies a child's , and here each leaf's low equals its own disc, so nothing decreases.
- Bridge test: : ✓ bridge. : ✓ bridge. : ✓ bridge. All three edges are bridges. Why this step? Each subtree can reach only itself, strictly below its parent — the textbook bridge condition.
- AP test: root 0 has one child → not AP. Node 1 (non-root): child 2 has ✓ → 1 is AP. Node 2 (non-root): child 3 has ✓ → 2 is AP. Node 3 is a leaf (no children) → not AP. APs = {1, 2}.
Verify: Remove node 1 → and : two components ✓. Remove node 2 → and ✓. Remove an endpoint 0 → still one piece → correctly NOT an AP. Bridges = 3, APs = {1,2}. ✓
Cell G note: the smallest chain, a single edge , is contained here: that edge is a bridge, and neither endpoint is an AP (removing an endpoint leaves one node, still "connected" as a single component). Endpoints are never cut vertices.
Example 3 — the hub / star root (cell C)
Forecast: 0 is the only thing tying the three arms together. Guess before reading.

- DFS from 0 visits 1 (dead end, back up), then 2 (dead end), then 3 → three separate tree children of the root. Why this step? There are no edges between 1, 2, 3, so DFS cannot go deeper from any of them; it returns to 0 and picks the next unvisited neighbour. That is what makes them sibling subtrees of the root.
- disc = low = ; no back edges exist.
- Root AP rule: children count of root → 0 is an articulation point. Why this step? The root has no ancestor to fall back on; if it holds independent subtrees, deleting it disconnects them from each other.
- Bridge test: each edge : ✓ → all 3 edges are bridges.
Verify: Remove 0 → : three components ✓ (AP confirmed). Remove edge → 2 isolated ✓ (bridge confirmed). Bridges = 3, APs = {0}. ✓
Example 4 — subtree hanging off a cycle (cells D + E, the equality tie)
Forecast: One edge is a lonely link, one node is a chokepoint, and there's a sneaky "back edge to itself" tie. Predict which edge, which node.

- DFS as tree edges; at 3 the edge is a back edge to ancestor 1. Why this step? 1 is already visited and is not 3's DFS parent (2 is), so closes the triangle as a back edge.
- disc = . Apply source 3 at 3: . Why this step? The triangle's escape hatch reaches up to disc-time 1 (node 1) — but no higher, because the back edge lands on 1, not on 0.
- Unwind (source 2): ; ; .
- Bridge test:
- : ? No.
- : ? No — it's a tie, is false. (cell E)
- : ? Yes → BRIDGE. (cell D)
- AP test (uses , so ties DO cut):
- Node 1 (non-root), child 2: ? Yes → 1 is an AP. This is the exact place where the tie matters: the edge is not a bridge (source of a back edge into 1), yet the vertex 1 is still critical.
- Node 2, child 3: ? No. Node 0 is root with one child → not AP.
Verify: Remove edge → alone, triangle separate → bridge ✓. Remove edge → still connected → NOT a bridge ✓. Remove vertex 1 → and : two components → 1 is AP ✓. Bridges = {(0,1)}, APs = {1}. ✓
Example 5 — a single vertex (cell F, degenerate)
Forecast: There is literally nothing to remove. Guess the counts.
- DFS from 0: the loop
for v in adj[0]never runs (empty adjacency).children = 0. Why this step? No neighbours means no tree edges and no back edges — the recurrence has only source 1: . - Root rule: children , which is not → 0 is not an AP.
- Bridge list stays empty — there is no edge to test.
Verify: Removing the only vertex leaves the empty graph. The component count goes from 1 to 0, which is not an increase — so by definition (removal must increase components) it is not an articulation point. Bridges = 0, APs = 0. ✓
Example 6 — a disconnected graph (cell H)
Forecast: The algorithm's outer for s in range(n) restarts DFS on each unvisited node. So it will handle P, then Q, as two independent runs. Predict each piece's answer, then combine.
- First DFS from 0 covers P: as in cell G, edge is a bridge, neither endpoint an AP. Why this step? The outer loop guarantees every component gets its own DFS root with , so Connected Components are analysed independently — no interaction leaks across pieces.
- After P, disc of 2,3,4 is still . The outer loop finds 2 unvisited → new DFS root 2, timer continues from where it left off (say ). Why this step? Timestamps keep counting globally, but that is harmless: comparisons only happen within one subtree, so cross-component times never mix.
- Q is a triangle → by cell A, 0 bridges, 0 APs inside Q.
- Combine: whole-graph bridges ; whole-graph APs .
Verify: Component count starts at 2. Removing edge → P splits → 3 components (increase) → bridge ✓. Removing edge → Q still a path , still connected → 2 components (no increase) → not a bridge ✓. Bridges = 1, APs = 0. ✓
Example 7 — the parallel-edge trap (cell I)
Forecast: There are two independent roads between the same pair of towns. Cutting one leaves the other. So — bridge or not? And will the naive code get it right?

- Truth first: with two parallel edges, removing one still leaves the other → neither edge is a bridge, and neither vertex is an AP. Why this step? Bridge means removal disconnects; a redundant twin prevents that.
- What the naive
v == parentcode does: DFS down edge #1 (tree edge). At 1, we look at neighbour 0 via edge #2. The code checksv == parent→0 == 0→ skips it, thinking it is the edge we came down on. But it isn't — it's the second edge! Why this step? Skipping by vertex identity cannot tell the two edges apart, so the genuine back-route (edge #2) is invisible. Then stays , and the bridge test fires → falsely reports a bridge. - Fix: skip the parent edge by edge-id, once. Pass the id of the edge you descended on; only skip that id. The second parallel edge is then treated as a proper back edge (source 3), lowering to , and is false → correctly no bridge.
Verify: With the edge-id fix, ; bridge test is false ✓. Removing one of the two edges physically leaves 0 and 1 still joined → not a bridge ✓.
Example 8 — real-world word problem (cell J)
Forecast: The loop A–B–C is robust; the tail C–D–E is a dangling chain. Which pipes and which stations are critical? Predict, then trace.

- Translate to a graph and DFS from 0(A): (tree edges), the edge is a back edge closing the loop, then (tree edges) down the tail. Why this step? Modelling "burst pipe → split" is exactly the bridge question; "shut station → split" is exactly the articulation question. The picture is the graph.
- Assign disc as we descend: for ; initialise (source 1). Why this step? Standard start — every vertex reaches at least itself.
- Back edge at 2 (source 3): lands on ancestor 0, so . In the tail there is no back edge, so and stay high. Why this step? The loop collapses its low to 0 (robust, like cell A); the tail keeps low = disc (fragile, like cell B). This split is the whole answer in miniature.
- Unwind (source 2): ; ; ; . Why this step? Each parent absorbs the best reach of its child's subtree; the tail's high lows never leak into the loop.
- Bridge test on every tree edge:
- loop edges : ? no. : ? no. — loop is bridge-free.
- : ? yes → pipe C–D is critical.
- : ? yes → pipe D–E is critical.
- AP test:
- Node 2(C), child 3: ✓ → station C is critical.
- Node 3(D), child 4: ✓ → station D is critical.
- Node 1(B), child 2: ? no → B not critical. Node 4(E) is a leaf → not critical. Root 0(A) has one tree child → not critical.
Verify: Burst pipe C–D → {A,B,C} vs {D,E}: split ✓. Burst A–B → A–C–B still connected via the loop → not critical ✓. Shut C → {A,B} vs {D,E}: split ✓. Shut D → {A,B,C} vs {E}: split ✓. Critical pipes = {C–D, D–E}, critical stations = {C, D}. ✓
Example 9 — exam twist: find both sets on a mixed graph (cell K)
Forecast: Two robust loops joined by one thin edge . Predict: the thin edge is the only bridge; the two nodes at its ends are the cut vertices. Write your guess, then check.
- DFS from 0: tree edges , then back edge closes loop A; from 1 the tree edge , then , and back edge closes loop B. Why this step? Two cycles means two escape hatches — each loop's nodes get a low that collapses to that loop's top; the joining edge has no loop covering it, so it stands alone.
- Assign disc as we descend: for ; initialise (source 1).
- Back edges (source 3): loop A gives . Loop B gives . Why this step? Loop B's back edge lands on 3, so its subtree reaches only down to disc-time 3 — never up to 1. That is the fingerprint of a bridge sitting above it.
- Unwind (source 2): ; ; at node 1, ; .
- Bridge test on every tree edge:
- Loop A: ? no; ? no.
- : ? yes → BRIDGE.
- Loop B: ? no; ? no.
- AP test:
- Node 1 (non-root), child 3: ✓ → 1 is an AP (its other child 2 gives ? no — but one qualifying child is enough).
- Node 3, child 4: ✓ → 3 is an AP.
- Root 0: one tree child (node 1) → not AP. Nodes 2,4,5: no failing child → not APs.
Verify: Remove edge → loop A {0,1,2} vs loop B {3,4,5}: split ✓ (only bridge). Remove vertex 1 → loop B side {3,4,5} cut from {0,2} → 1 is AP ✓. Remove vertex 3 → {4,5} cut from {0,1,2} → 3 is AP ✓. Bridges = {(1,3)}, APs = {1,3}. ✓
The matrix, filled in
Recall Which example covered which cell?
A→Ex1, B→Ex2, C→Ex3, D+E→Ex4, F→Ex5, G→Ex2/Ex6, H→Ex6, I→Ex7, J→Ex8, K→Ex9. Every cell is worked.
Recall One-line reflex
Bridge when (strict, edge); AP-nonroot when (equality, vertex); AP-root when it has DFS children.
Related structures you can now read the same way: Biconnected Components (maximal chunks with no internal AP), Bridge Trees / 2-edge-connected components (contract every non-bridge into a node), and the directed cousin Strongly Connected Components - Tarjan which reuses the very same low-link idea.