Algorithm Search⌘K

Proofs: Hopcroft-Tarjan biconnectivity algorithm

These are the human proofs of Hopcroft-Tarjan biconnectivity algorithm, at full length.

One depth-first search finds the articulation points, the bridges and the blocks full

This proof shows: correctness.

Let G=(V,E)G = (V, E) be an undirected graph. Parallel edges and loops are allowed, and every edge has its own identifier. Loops are output as blocks by line L2 and are skipped by the search (the test v≠uv \neq u of line L6); a loop lies on no cycle with another edge and changes no articulation point and no bridge, so from here on GG has no loops.

Depth-first search facts. The calls of line L3 build a depth-first forest. An edge is a tree edge if it is pushed by line L8, and every other edge is a back edge. Since the search skips the tree edge into uu only by its identifier, a parallel copy of a tree edge is a back edge. Each back edge joins a vertex xx to a proper ancestor ww of xx (edge classification); we call xx its lower end. For a tree edge, the lower end is the child. Write T(v)T(v) for the subtree of vv, and

ℓ(v)=min⁡({d[v]}∪{d[w]:a back edge joins some x∈T(v) to w}).\ell(v) = \min\big(\{ d[v] \} \cup \{ d[w] : \text{a back edge joins some } x \in T(v) \text{ to } w \}\big).

Lemma 1. When VISIT(v,p)(v, p) returns, low[v]=ℓ(v)\mathrm{low}[v] = \ell(v).

Proof. By induction on the order in which the calls return. Line L5 sets low[v]=d[v]\mathrm{low}[v] = d[v]. Each edge e={v,w}e = \{v, w\} at vv other than pp is one of three kinds. If d[w]=0d[w] = 0, it becomes a tree edge, and line L9 takes the minimum with low[w]=ℓ(w)\mathrm{low}[w] = \ell(w) by induction. If d[w]<d[v]d[w] < d[v], ww is an ancestor of vv, so ee is a back edge with lower end vv, and line L15 takes d[w]d[w]. If d[w]>d[v]d[w] > d[v], ww is a descendant of vv that is already visited, so ee is a back edge with lower end ww, already counted in ℓ\ell of a child; its value d[v]d[v] is not below d[v]d[v] anyway. So low[v]\mathrm{low}[v] is the minimum over vv, its own back edges and the subtrees of its children, which is ℓ(v)\ell(v). □\square

Lemma 2 (where an edge out of a subtree can go). Let (u,v)(u, v) be a tree edge. Every edge with exactly one end in T(v)T(v) is the tree edge (u,v)(u, v) or a back edge from a vertex of T(v)T(v) to a proper ancestor of vv, and the smallest discovery time among the ends of such back edges is ℓ(v)\ell(v) when it is below d[v]d[v].

Proof. A tree edge with one end in T(v)T(v) is (u,v)(u, v). A back edge joins a vertex to an ancestor, so if one end is in T(v)T(v) and the other is not, the lower end is in T(v)T(v) and the upper end is an ancestor of vv outside T(v)T(v). The rest is the definition of ℓ\ell. □\square

Theorem 1 (bridges, line L13). An edge ee is a bridge if and only if it is a tree edge (u,v)(u, v) with low[v]>d[u]\mathrm{low}[v] > d[u].

Proof. A back edge from xx to ww lies on the cycle formed with the tree path from ww to xx, so it is not a bridge. For a tree edge (u,v)(u, v), the graph G−eG - e joins T(v)T(v) to the rest if and only if some other edge has exactly one end in T(v)T(v). By Lemma 2, such an edge is a back edge from T(v)T(v) to an ancestor ww of uu (possibly uu itself, through a parallel copy of ee), which has d[w]≤d[u]d[w] \le d[u]. So ee is not a bridge if and only if ℓ(v)≤d[u]\ell(v) \le d[u]. Lemma 1 finishes the proof. □\square

Theorem 2 (articulation points, lines L4 and L12). A root rr is an articulation point if and only if it has at least two children. A vertex uu that is not a root is one if and only if it has a child vv with low[v]≥d[u]\mathrm{low}[v] \ge d[u].

Proof. Root. By Lemma 2 no edge joins the subtrees of two children of rr, since a back edge goes to an ancestor. With two or more children, G−rG - r splits them. With one child vv, G−rG - r contains the tree T(v)T(v), which spans the rest of the component.

Not a root. Suppose a child vv has ℓ(v)≥d[u]\ell(v) \ge d[u]. By Lemma 2, every edge that leaves T(v)T(v) goes to an ancestor ww of vv with d[w]≥d[u]d[w] \ge d[u], so to uu. In G−uG - u, the set T(v)T(v) has no edge to the root r≠ur \neq u, so uu is an articulation point. Conversely, suppose every child vv has ℓ(v)<d[u]\ell(v) < d[u]. Then each T(v)T(v) has a back edge to a proper ancestor of uu. The vertices of the component that are not in T(u)T(u) form a subtree that contains rr, so they stay connected in G−uG - u, and each T(v)T(v) is joined to them. So G−uG - u has as many components as GG. □\square

Theorem 3 (blocks, line L11). Each block of GG is output exactly once, as the set of edges popped by line L11.

Proof. Call a vertex yy that is not a root a head if low[y]≥d[π(y)]\mathrm{low}[y] \ge d[\pi(y)], where π(y)\pi(y) is the parent of yy; these are the children for which line L10 succeeds. Every child of a root is a head. For an edge ff with lower end xx, let h(f)h(f) be the first head on the tree path from xx up to the root, starting at xx. Let R(y)R(y) be T(y)T(y) without the subtrees T(y′)T(y') of the heads y′≠yy' \neq y inside T(y)T(y).

Step 1: line L11 pops exactly the edges ff with h(f)=yh(f) = y when it closes the tree edge (π(y),y)(\pi(y), y). The edges pushed from the push of (π(y),y)(\pi(y), y) until VISIT(y)(y) returns are the edges whose lower end is in T(y)T(y), since line L8 and line L15 push an edge when its lower end is the current vertex. The pops for heads inside T(y)T(y) happen earlier, since a call returns after its descendants; by induction they removed the edges whose hh is such a head. The remaining edges above (π(y),y)(\pi(y), y) on the stack are those with h(f)=yh(f) = y.

Step 2: all ends of an edge ff with h(f)=yh(f) = y lie in R(y)∪{π(y)}R(y) \cup \{\pi(y)\}. The lower end xx is in R(y)R(y). If ff is a back edge to ww, then d[w]≥ℓ(x)≥ℓ(y)≥d[π(y)]d[w] \ge \ell(x) \ge \ell(y) \ge d[\pi(y)], so ww is on the tree path from π(y)\pi(y) to xx; an inner vertex of this path in some T(y′)T(y') would put xx in T(y′)T(y') too, so w∈R(y)∪{π(y)}w \in R(y) \cup \{\pi(y)\}.

Step 3: two edges on a common cycle have the same hh. Let y′y' be a head. By Lemma 2 and ℓ(y′)≥d[π(y′)]\ell(y') \ge d[\pi(y')], every edge with exactly one end in T(y′)T(y') has its other end at π(y′)\pi(y'). A cycle that enters T(y′)T(y') must enter and leave it through π(y′)\pi(y'), and it passes π(y′)\pi(y') only once, so the whole cycle lies in T(y′)∪{π(y′)}T(y') \cup \{\pi(y')\}. So every cycle CC either lies in T(y′)∪{π(y′)}T(y') \cup \{\pi(y')\} or has no vertex in T(y′)T(y'). Take the deepest head yy with C⊆T(y)∪{π(y)}C \subseteq T(y) \cup \{\pi(y)\}; it exists because CC lies in the subtree of one child of a root. Every head y′≠yy' \neq y inside T(y)T(y) has T(y′)T(y') disjoint from CC, so all lower ends of edges of CC are in R(y)R(y), and all edges of CC have h=yh = y.

Step 4: the edges with h=yh = y are pairwise on common cycles. Write u=π(y)u = \pi(y). Let (a,b)(a, b) be a tree edge with b∈R(y)b \in R(y) and b≠yb \neq y. Then bb is not a head, so ℓ(b)<d[a]\ell(b) < d[a], and some back edge goes from x′∈T(b)x' \in T(b) to a proper ancestor of aa. If x′x' were in T(y′)T(y') for a head y′y' inside T(b)T(b), the edge would end at π(y′)∈T(b)\pi(y') \in T(b), which is not an ancestor of aa; so x′∈R(y)x' \in R(y). The cycle of this back edge and the tree path contains (a,b)(a, b) and the tree edge into aa. So by induction upward, every tree edge with lower end in R(y)R(y) lies on a common cycle with (u,y)(u, y), in the sense of the relation ≡\equiv of the biconnected components page. A back edge ff with h(f)=yh(f) = y from xx to ww lies on a cycle with the first tree edge below ww on the path to xx, and by Step 2 that tree edge has its lower end in R(y)R(y). Since ≡\equiv is transitive, all edges with h=yh = y are in one class.

Steps 3 and 4 show that the classes of ≡\equiv on the non-loop edges are exactly the sets {f:h(f)=y}\{ f : h(f) = y \} for the heads yy, each one non-empty because it contains (π(y),y)(\pi(y), y). Step 1 shows that line L11 outputs each of these sets once. □\square

Termination and output. Each vertex is visited once, each list entry is read once, and each non-loop edge is pushed once and popped once. So the procedure stops, it outputs every block once (Theorem 3 and line L2), and it marks exactly the articulation points and the bridges (Theorems 1 and 2). ■\blacksquare

Back to Hopcroft-Tarjan biconnectivity algorithm