Articulation points: fragile vertices
Picture
In A—B—C with B—D, removing B separates A, C, and D.
Predict
Why does the bridge test use > while a non-root articulation test uses ≥?
Walk through the small example
Removing the vertex also removes the equal endpoint. DFS low-link summaries reveal child subtrees lacking a route above the parent vertex.
Mental model and complete Python solution
Ask whether a child branch can climb above its parent without that parent. Reaching the parent itself is insufficient when the parent vertex disappears.
What the function promises: Return sorted articulation vertices for a simple undirected graph, including disconnected components.
def articulation_points(n, edges):
graph = [[] for _ in range(n)]
for u, v in edges:
graph[u].append(v); graph[v].append(u)
discovered = [-1] * n
low = [0] * n
answer, timer = set(), 0
def visit(u, parent):
nonlocal timer
discovered[u] = low[u] = timer
timer += 1
children = 0
for v in graph[u]:
if v == parent: continue
if discovered[v] == -1:
children += 1
visit(v, u)
low[u] = min(low[u], low[v])
if parent != -1 and low[v] >= discovered[u]:
answer.add(u)
else:
low[u] = min(low[u], discovered[v])
if parent == -1 and children > 1:
answer.add(u)
for start in range(n):
if discovered[start] == -1: visit(start, -1)
return sorted(answer)
assert articulation_points(4, [(0,1),(1,2),(1,3)]) == [1]
assert articulation_points(3, [(0,1),(1,2),(2,0)]) == []
Work and storage: O(V+E) time and O(V) auxiliary storage, including recursion.
When to recognize it: DFS low-link summaries reveal child subtrees lacking a route above the parent vertex.
Check before applying it: Roots and parallel edges need careful treatment; recursion may overflow on deep graphs.
Change one rule
The graph can contain parallel edges.
See what changes
Track edge IDs and skip only the incoming edge, as in the bridge lesson.
Connect
bridges: Reuse discovery and low values with a different removal question.
tree summaries: Child subtrees report their earliest reachable ancestor.