Algorithm Search⌘K

Proofs: Lempel-Even-Cederbaum st-numbering algorithm

These are the human proofs of Lempel-Even-Cederbaum st-numbering algorithm, at full length.

Correctness of the st-numbering algorithm full

This proof shows: correctness, termination.

Setting. GG is a finite undirected graph with n≥2n \ge 2 vertices, s≠ts \ne t, and the edge stst is treated as present. TT is the DFS tree of line L1, rooted at ss. Since the search from ss follows stst first and the whole search from tt ends before ss looks at another edge, tt is a child of ss, and every vertex reached later from ss is another child of ss. pre(v)\mathrm{pre}(v) is the preorder number and low(v)\mathrm{low}(v) is the vertex of smallest preorder among vv, the descendants of vv, and the ends of back edges from them.

Termination and cost. The search, the check and the loop each take finitely many steps, O(n+m)O(n + m) in total.

Line L2 is the right test

Lemma 1. Line L2 fails if and only if G+stG + st is disconnected or has a cut vertex. If it does not fail, then tt is the only child of ss, and low(v)\mathrm{low}(v) is a proper ancestor of p(v)p(v) for every v∉{s,t}v \notin \{s, t\}.

Proof. If some vertex is not reached, G+stG + st is disconnected. Otherwise TT spans G+stG + st, and by the standard characterization of cut vertices with low points (see the articulation point pages): the root ss is a cut vertex if and only if it has at least two children, and a non-root uu is a cut vertex if and only if it has a child vv with pre(low(v))≥pre(u)\mathrm{pre}(\mathrm{low}(v)) \ge \mathrm{pre}(u). If ss has a second child cc, then p(c)=sp(c) = s and low(c)≥pre(s)=0\mathrm{low}(c) \ge \mathrm{pre}(s) = 0 is detected by line L2. So line L2 checks exactly both conditions. When it passes, pre(low(v))<pre(p(v))\mathrm{pre}(\mathrm{low}(v)) < \mathrm{pre}(p(v)), and low(v)\mathrm{low}(v) is an ancestor of vv (the end of a back edge from the subtree of vv is an ancestor of vv in a DFS tree of an undirected graph, or lies in the subtree), so it is a proper ancestor of p(v)p(v). □\square

When G+stG + st is not 2-connected, no st-numbering exists. Suppose one exists, and let uu be any vertex. From every vertex x≠ux \ne u there is a path of increasing numbers to tt and a path of decreasing numbers to ss, and these two paths meet only in xx, so at least one of them avoids uu (if u=su = s or u=tu = t, take the other one). So every vertex other than uu reaches ss or tt in G+st−uG + st - u, and if neither ss nor tt is uu, the edge stst joins them. So G+st−uG + st - u is connected for every uu, and G+stG + st is connected; with n≥3n \ge 3 this means 2-connected, and for n=2n = 2 the graph G+stG + st is K2K_2. So failing is the right answer.

From now on assume that line L2 passes.

The list

The loop processes vertices in preorder, so p(v)p(v) is in LL when vv is inserted. Insertions never change the relative order of vertices already in LL.

Lemma 2 (no jumping). When vv is inserted next to p(v)p(v), for every vertex x≠p(v)x \ne p(v) in LL, the vertices vv and p(v)p(v) lie on the same side of xx, and they stay so forever.

Proof. vv is placed between p(v)p(v) and its neighbour in LL on one side, so no vertex lies between vv and p(v)p(v) at that moment. Relative order is never changed later. □\square

For a vertex xx that has a child in LL, let cxc_x be the child of xx inserted most recently.

Lemma 3 (sides of subtrees). At every moment, for every xx with a child in LL: all vertices of the subtree of cxc_x that are in LL lie before xx if sign(x)=+\mathrm{sign}(x) = +, and after xx if sign(x)=−\mathrm{sign}(x) = -.

Proof. When cxc_x is inserted, line L6 or L8 sets sign(x)\mathrm{sign}(x) to ++ if cxc_x goes before xx and to −- if it goes after, and the subtree of cxc_x in LL is {cx}\{c_x\}. Afterwards, sign(x)\mathrm{sign}(x) changes only when a new child of xx is inserted, which replaces cxc_x. Every later vertex vv of the subtree of cxc_x has its parent in that subtree, and p(v)≠xp(v) \ne x; by Lemma 2 it lands on the same side of xx as p(v)p(v), which by induction is the side of cxc_x. □\square

Lemma 4 (the low point is opposite the parent). For every v∉{s,t}v \notin \{s, t\}, after its insertion, low(v)\mathrm{low}(v) lies on the other side of vv from p(v)p(v).

Proof. Let w=low(v)w = \mathrm{low}(v), a proper ancestor of p(v)p(v) by Lemma 1. Then p(v)p(v) is in the subtree of the child of ww on the path to vv, and this child is cwc_w at the time vv is inserted, because in preorder the subtree of a child is processed completely before the next child. By Lemma 3, if sign(w)=−\mathrm{sign}(w) = - then p(v)p(v) lies after ww; line L6 puts vv directly before p(v)p(v), so ww lies before vv and p(v)p(v) after it. If sign(w)=+\mathrm{sign}(w) = +, symmetrically p(v)p(v) lies before ww, line L8 puts vv directly after p(v)p(v), and ww lies after vv. □\square

Lemma 5. ss is first and tt is last in the final list.

Proof. A vertex is inserted before p(v)p(v) or after p(v)p(v), and p(v)≠sp(v) \ne s for v∉{s,t}v \notin \{s, t\} by Lemma 1, so nothing is inserted before ss. A vertex is inserted after tt only if p(v)=tp(v) = t and sign(low(v))=+\mathrm{sign}(\mathrm{low}(v)) = +. Then low(v)\mathrm{low}(v) is a proper ancestor of tt, so it is ss. The sign of ss is set to −- at line L3 and changes only when a child of ss is inserted, which never happens since tt is its only child. So nothing is inserted after tt. □\square

Main theorem

Theorem. If line L2 passes, the numbering of line L9 is an st-numbering of G+stG + st, and every vertex v∉{s,t}v \notin \{s, t\} has neighbours in GG on both sides.

Proof. By Lemma 5, num(s)=1\mathrm{num}(s) = 1 and num(t)=n\mathrm{num}(t) = n. Let v∉{s,t}v \notin \{s, t\}. The parent p(v)p(v) is a neighbour of vv in GG (the only tree edge not in GG might be stst, and v≠tv \ne t). We find a neighbour on the other side, which by Lemma 4 is the side of w=low(v)w = \mathrm{low}(v).

If vv has a back edge to ww, then ww is such a neighbour.

Otherwise ww is reached from a proper descendant of vv, so there is a child cc of vv with low(c)=w\mathrm{low}(c) = w. Suppose sign(w)=−\mathrm{sign}(w) = - when vv is inserted; then vv goes before p(v)p(v) and ww lies before vv. Between the insertions of vv and cc the loop inserts only descendants of vv (preorder), whose parents are vv or descendants of vv; none of them is ww, because ww is a proper ancestor of p(v)p(v). So sign(w)\mathrm{sign}(w) is still −- when cc is inserted, and line L6 puts cc directly before p(c)=vp(c) = v. So cc lies on the side of ww, opposite p(v)p(v). The case sign(w)=+\mathrm{sign}(w) = + is symmetric. In both cases cc is a neighbour of vv in GG on the other side.

So every v∉{s,t}v \notin \{s, t\} has a neighbour with a smaller number and one with a larger number. ■\blacksquare

Back to Lempel-Even-Cederbaum st-numbering algorithm