由于离散课需要回课,就去学了Hopcroft和Tarjan老爷子在1974年提出的 O ( V ) O(V) O(V) 时间内判断一个图是否是平面图的算法,然后上课的时候讲。原文是 John Hopcroft and Robert Tarjan. 1974. Efficient Planarity Testing.J. ACM21, 4 (October 1974), 549-568. 这是链接。
用了好一些时间才完全理解整个算法。想懂之后其实并不难,但真真实实非常巧妙。
感觉论文读起来困难是因为一开始没有把握到算法的整体思想,所以一度看的怀疑人生。一旦知道文章在干嘛,很多地方读起来就十分自然了。
课上听某同学讲,某年清华集训貌似就出了一道平面图判定的模板题,也不清楚标算是不是用的这个算法。
一些记号
简单路径:每个点至多被经过一次。
环:除起点外,每个点至多被经过一次。
割点:删掉该点后原图不再连通。
双连通图:连通且不包含割点的图。
p : v ⇒ ∗ w p:v\Rightarrow ^* w p:v⇒∗w: p p p 是一条从 v v v 到 w w w 的路径。
树:根为 r r r 的有向图 T T T,从 r r r 出发可以到达所有点, r r r 没有入边,其余每个点恰好有一条入边。
v → w v\to w v→w: T T T 中一条 v v v 到 w w w 的边,称 v v v 为 w w w 的父亲, w w w 为 v v v 的儿子。
v → ∗ w v\to ^* w v→∗w: T T T 中 v v v 到 w w w 的路径,称 v v v 为 w w w 的祖先, w w w 为 v v v 的后代。
d f s dfs dfs 树
设 G G G 是一个连通无向图。从一个点开始对 G G G 做 d f s dfs dfs,令经过的边为树边,得到 G G G 的生成树 T T T,称 T T T 为 G G G 的 d f s dfs dfs 树。
若边 ( v , w ) (v,w) (v,w) 不是树边,且 v v v 和 w w w 在 T T T 中有祖先关系,不妨设 w w w 是 v v v 的祖先,则称 ( v , w ) (v,w) (v,w) 为一条返祖边,记为 v − → w v-\to w v−→w。
因为是通过 d f s dfs dfs 遍历图 G G G,所以 G G G 中的每一条非树边必然是返祖边。
令 d f n ( x ) dfn(x) dfn(x) 表示 x x x 被到达的时刻, l o w ( x ) low(x) low(x) 表示通过 x x x 的子树中的返祖边能到达的节点的 d f n dfn dfn 的最小值,形式化定义就是 l o w ( x ) = min { d f n ( x ) , min ( u , v ) ∈ E f , u ∈ s u b t r e e ( x ) d f n ( v ) } low(x)=\min\{dfn(x),\min_{(u,v)\in E_f,u\in subtree(x)}dfn(v)\} low(x)=min{ dfn(x),(u,v)∈Ef,u∈subtree(x)mindfn(v)}
其中 E f E_f Ef 表示返祖边构成的集合。同时令 l o w 2 ( x ) low2(x) low2(x) 表示次小值。
算法思想
对于一个连通图 G G G,它是平面图当且仅当它的每一个点双连通分量均为平面图。因此只需要考虑一个双连通图的平面图判定问题。
先找出 G G G 的 d f s dfs dfs 树 T T T,将每个点 x x x 重标号为 d f n ( x ) dfn(x) dfn(x),并将边重定向:令树边从父亲指向儿子,返祖边从后代指向祖先。找到 G G G 中的一个环 c : 1 → v 1 → v 2 → ⋯ → v n − → 1 c:1\to v_1\to v_2\to \cdots\to v_n-\to 1 c:1→v1→v2→⋯→vn−→1,环中只有最后一条边是返祖边。删掉 c c c 后会得到很多个连通块,称之为 segment。每个 segment 要么是一条 v i → ∗ v j v_i\to^*v_j vi→∗vj 的返祖边,要么由某个 v i v_i vi 的儿子 u u u 的子树中的所有边(包括返祖边)组成。则每个 segment 最后必然全落在 c c c 的内侧或外侧。
每个 segment 都对应一个环 c u : v i → u ⇒ ∗ l o w ( u ) → ∗ v i c_u:v_i\to u\Rightarrow ^*low(u)\to ^*v_i cu:vi→u⇒∗low(u)→∗vi,可将 c u c_u cu 看作该 segment 的外轮廓。按照从外向内的顺序嵌入 segment,则该 segment 的其他部分可被嵌入到 c u c_u cu 的内部,不影响其他已经被嵌入的 segment。
对于一个新加入的 segment,先考虑在已经嵌入了环 c c c 和前面被加入的 segment 的基础上,其外轮廓能否被嵌入到平面中。若不能嵌入,则 G G G 不是平面图。否则保留 c u c_u c