Algorithm Search⌘K

Proofs: Gabow-Myers spanning tree enumeration algorithm

These are the human proofs of Gabow-Myers spanning tree enumeration algorithm, at full length.

The Gabow-Myers backtracking lists every spanning tree exactly once full

This proof shows: correctness, termination.

Let G=(V,E)G = (V, E) be a finite undirected graph with V={0,…,n−1}V = \{0, \dots, n - 1\}, n≥1n \ge 1. Parallel edges are distinct edges, and self-loops are allowed. During the run, some edges are deleted. The current graph G′G' is GG without the deleted edges. For an edge set TT, let V(T)V(T) be the set {0}\{0\} together with the ends of the edges of TT. An edge leaves V(T)V(T) if it has exactly one end in V(T)V(T).

Facts

Fact 1. Let HH be a connected graph, and let TT be a set of edges of HH that forms a tree on V(T)V(T). Then some spanning tree of HH contains TT.

Proof. Start from TT. While the edge set does not span VV, some edge of HH leaves the set of reached vertices, because HH is connected. Adding it keeps the set a tree. After n−1−∣T∣n - 1 - |T| steps, the set is a spanning tree that contains TT. □\square

Fact 2. If TT is a tree on V(T)≠VV(T) \ne V, then every spanning tree S⊇TS \supseteq T of a graph HH contains an edge of HH that leaves V(T)V(T).

Proof. SS connects a vertex of V(T)V(T) to a vertex outside it, and the path between them in SS has an edge that leaves V(T)V(T). □\square

The invariant

Call a state of a call GROW(T,F)(T, F) good if the following hold:

  • (a) TT is a tree on V(T)V(T), and T⊆G′T \subseteq G'.
  • (b) G′G' is connected.
  • (c) FF holds exactly the edges of G′G' that leave V(T)V(T), each once.

Lemma. If GROW(T,F)(T, F) is called in a good state, then it terminates. It outputs each spanning tree of G′G' that contains TT exactly once, and nothing else. On return, G′G' and FF are as they were at the call.

Proof. By induction on k=n−1−∣T∣k = n - 1 - |T|.

Base, k=0k = 0. By (a), TT is a tree with n−1n - 1 edges, so it is a spanning tree. It is the only spanning tree that contains TT. Line L1 outputs it and returns without changing anything.

Step, k>0k > 0. Then ∣V(T)∣=∣T∣+1<n|V(T)| = |T| + 1 < n. Let G1′=G′G'_1 = G' be the current graph at the call. Let e1,e2,…e_1, e_2, \dots be the edges popped at line L4 in the successive iterations, and let Gj′G'_j be the current graph at the start of iteration jj. Line L8 gives Gj+1′=Gj′−ejG'_{j+1} = G'_j - e_j, and line L7 together with the induction hypothesis gives that the recursive call changes nothing. We show by induction on jj that iteration jj starts with Gj′G'_j connected and with FF equal to the set of edges of Gj′G'_j that leave V(T)V(T).

For j=1j = 1, this is (b) and (c). Suppose it holds for jj. The graph Gj′G'_j is connected and V(T)≠VV(T) \ne V, so some edge of Gj′G'_j leaves V(T)V(T), and FF is not empty. So line L4 pops an edge ej=(v,w)e_j = (v, w) with v∈V(T)v \in V(T) and w∉V(T)w \notin V(T). Line L5 removes the edges of FF that join V(T)V(T) to ww and adds the edges of Gj′G'_j from ww to V∖(V(T)∪{w})V \setminus (V(T) \cup \{w\}). Afterwards FF holds exactly the edges of Gj′G'_j that leave V(T)∪{w}=V(T∪{ej})V(T) \cup \{w\} = V(T \cup \{e_j\}). The set T∪{ej}T \cup \{e_j\} is a tree on that vertex set, because eje_j adds the new vertex ww. So the call at line L6 is made in a good state, with k−1k - 1, and the induction hypothesis applies. Line L7 restores FF to the edges of Gj′G'_j that leave V(T)V(T), minus eje_j. Line L8 deletes eje_j. So FF is now the set of edges of Gj+1′G'_{j+1} that leave V(T)V(T). If the loop continues, then Gj+1′G'_{j+1} is connected, by the test at lines L9 and L10. This completes the induction on jj.

Termination. Each iteration deletes an edge of the finite graph GG, and each recursive call terminates by the induction hypothesis. So the loop runs at most ∣E∣|E| times. Let qq be the number of iterations. Then Gq+1′=G′−{e1,…,eq}G'_{q+1} = G' - \{e_1, \dots, e_q\} is disconnected.

What is output. By the induction hypothesis, iteration jj outputs exactly the spanning trees of Gj′G'_j that contain T∪{ej}T \cup \{e_j\}, each once. These are the spanning trees SS of G′G' with S⊇TS \supseteq T, ej∈Se_j \in S and e1,…,ej−1∉Se_1, \dots, e_{j-1} \notin S. Call this set Sj\mathcal{S}_j.

  • Disjoint. If i<ji < j, every tree in Si\mathcal{S}_i contains eie_i and every tree in Sj\mathcal{S}_j avoids it. So no tree is output twice.
  • Complete. Let SS be a spanning tree of G′G' with S⊇TS \supseteq T. If SS contains none of e1,…,eqe_1, \dots, e_q, then SS is a spanning tree of the disconnected graph Gq+1′G'_{q+1}, which is impossible. So SS contains some eje_j. Taking the least such jj gives S∈SjS \in \mathcal{S}_j.
  • Only trees that contain TT. Every output tree lies in some Sj\mathcal{S}_j.

Restoration. Line L11 undeletes e1,…,eqe_1, \dots, e_q, so the current graph is G′G' again. It pushes eq,…,e1e_q, \dots, e_1 back onto FF, with e1e_1 on top, which reverses the pops of line L4. Lines L7 and L8 left the rest of FF as it was. So FF is as it was at the call. □\square

The theorem

Theorem. If GG is connected, the top-level call outputs each spanning tree of GG exactly once and terminates. If GG is disconnected, it outputs nothing.

Proof. If GG is disconnected, it has no spanning tree, and the top level returns before calling GROW. Otherwise, the call GROW(∅,F)(\emptyset, F), with FF the non-loop edges at vertex 0, is made in a good state. T=∅T = \emptyset is a tree on V(∅)={0}V(\emptyset) = \{0\}, G′=GG' = G is connected, and the edges that leave {0}\{0\} are exactly the non-loop edges at 0. Every spanning tree contains ∅\emptyset. The lemma then gives the claim. ■\blacksquare

Corollary (no dead ends). Every call of GROW outputs at least one tree.

Proof. Every call is made in a good state. By Fact 1, the connected graph G′G' has a spanning tree that contains TT, and the lemma says the call outputs it. □\square

So the recursion tree has NN leaves, its depth is at most n−1n - 1, and it has at most (n−1)N+1(n - 1)N + 1 nodes. This is the count used in the complexity analysis. Fact 2 is the reason the loop can stop at a bridge: once Gj+1′G'_{j+1} is disconnected, no remaining tree avoids e1,…,eje_1, \dots, e_j.

Back to Gabow-Myers spanning tree enumeration algorithm