平面圖判定


原論文:https://www.cs.princeton.edu/courses/archive/fall05/cos528/handouts/Efficient Planarity.pdf
一種 \(O(n)\) 判斷圖平面性的做法

兩個引理

引理 1:一個圖是平面圖的必要條件是 \(m\le 3n-6\)
廣為人知

引理 2:在一個平面圖中,設 \(p_1,p_2,p_3\) 是三條從 \(x\)\(y\) 的路徑,任意兩條只有 \(x,y\) 兩個公共點,設其第一條邊分別是 \((x,v_1),(x,v_2),(x,v_3)\),其最后一條邊分別是 \((w_1,y),(w_2,y),(w_3,y)\),若 \(x\) 周圍的邊按照順時針順序依次是 \((x,v_1),(x,v_2),(x,v_3)\),那么 \(y\) 周圍的邊按照順時針順序是 \((w_1,y),(w_3,y),(w_2,y)\)
證明可以根據 Jordan curve theorem 直接得到,而其證明比較復雜

概述

原論文的圖都是從下往上畫的,於是下面想象一顆搜索樹的時候盡量讓根在最底下

對於圖 \(G\),顯然他是一個平面圖等價於他的所有點雙連通分量都是平面圖,可以把每個雙連通分量圍繞在割點周圍
那么現在討論 \(G\) 是一個點雙連通圖的情況
\(G\) dfs 建出 dfs 樹,記錄下 dfs 序並將 \(u\) 重標號\(dfn(u)\),然后將每條樹邊重定向為 dfs 樹上的父親指向兒子,每條返祖邊重定向為后代指向祖先(無向圖的 dfs 樹只有樹邊和返祖邊)
下面的所有討論都基於如上的假設

現在找到 \(G\) 中的一個環:\(C:1\rightarrow u_1\rightarrow u_2\rightarrow \cdots \rightarrow u_n \rightarrow 1\),在整個環上,前面的邊都是樹邊,只有 \(u_n \rightarrow 1\) 是返祖邊
現在刪掉 \(C\),那么 \(G\) 中會剩下若干個連通塊,我們稱之為 Segment;對於每個 Segment,要么是由單一的一個返祖邊組成,要么是某 \(u_i\) 的一個兒子 \(v\) 以及他子樹中的所有邊(從子樹出發的所有樹邊、返祖邊)以及邊 \((u_i,v)\) 組成
由於每個 Segment 中不會存在形如 \(x\rightarrow u_i\rightarrow y\) 的路徑,所以每個 Segment 都會全部在環 \(C\) 的內側或外側

下面用 \(x\rightarrow y\) 表示一條從 \(x\)\(y\) 的邊,用 \(x\Rightarrow y\) 表示一條 \(x\)\(y\) 的經過多條邊的路徑
考慮尋找雙連通分量時的 tarjan 算法,定義出 \(low(u)\),類似的,定義出嚴格次小值 \(low2(u)\)(當 \(low(u)=low2(u)=u\) 時,可忽略嚴格的要求)
考慮每個 Segment 對應了一個環 \(C_v:u_i\rightarrow v\Rightarrow low(v)\Rightarrow u_i\),我們將這個環作為此 Segment 的 外輪廓,那么若按照從外往里的順序嵌入,則這個 Segment 的其他部分都被嵌入到了 \(C_v\) 的里面,因此就不會影響到其他的 Segment

那么有一個大概的思路:

  • 依次考慮 \(G\) 的每一個 Segment,所在嵌入環 \(C\) 和其他已經嵌入的 Segment 后,該 Segment 的外輪廓 \(C_v\) 不能在被嵌入,則 \(G\) 不是平面圖
  • 否則,嘗試遞歸判斷該 Segment 是否可以平面嵌入
  • 具體的,就是把 \(C_v\) 當作遞歸下去后的環 \(C\),然后刪掉他就又得到了若干小 Segment

Pathfinding

首先考慮如何找到一條合適的路徑 \(v\Rightarrow low(v)\) 將其作為外輪廓的一部分
一個想法是讓 \(low\) 最小的邊在鄰接表中先被遍歷到,然后沿着鄰接表往下走
具體的,考慮給當前 Segment 的邊集划分為若干個子集,每個子集是一條路徑(或者按照上文說是一個輪廓),先給一個點的所有出邊進行排序,定義邊權:

\[w(u,v)=\begin{cases} 2v & u\rightarrow v\ \text{是返祖邊}\\ 2low(v) & u\rightarrow v\ \operatorname{and}\ low2(v)\ge u\\ 2low(v)+1 & u\rightarrow v\ \operatorname{and}\ low2(v)<u\\ \end{cases} \]

對這些邊權從小到大桶排序來保證復雜度
引入 \(low2\) 是因為要把 \(low2\) 更小的路徑放在內側防止它把別的路徑擋住(具體的用處會在后面的某些證明中用到)
排序后遍歷時,依次經過每一條邊:經過一條樹邊,把他加進正在構建的那條路徑中;經過返祖邊,將這條邊作為目前構建的這條路徑的最后一條邊,下一條經過的邊會在一個新的路徑中
如圖(注意這個圖是從下往上畫的搜索樹,左圖是找到的若干路徑,右圖是划分出的若干 Segment):

那么這些路徑的形態,就是若干條(可能為零)樹邊加上一條返祖邊結尾,因為圖是雙連通的,那么有 \(low(1)=1\) 以及 \(low(u)<u(u\neq 1)\)
於是對於路徑 \(p:s\Rightarrow t\) 必定是 \(s=t=1\),形成一個環;或者 \(p\) 是一條簡單路徑,\(t\)\(s\) 的祖先,路徑 \(t\Rightarrow s\) 完全由樹邊組成

考慮其他性質:

性質 1:若有路徑 \(p:s\Rightarrow f\),那么當走過這個路徑上的第一條邊時,考慮所有還沒有被用到的返祖邊(每條路徑對應一個返祖邊),\(f\) 是通過 \(s\) 的某后代的一條返祖邊可以到達的最小的點;對於路徑中的一個不是端點的節點 \(x\)\(f\) 是他可以到達的最小點
顯然,這兩點都可以通過對鄰接表的排序方式來簡單理解

性質 2:若有 \(p_1:s_1\Rightarrow f_1,p_2:s_2\Rightarrow f_2\) 是按照如上方式生成的兩條路徑,如果 \(p_1\)\(p_2\) 之前被生成,且 \(s_1\)\(s_2\) 的祖先,那么有 \(f_1\le f_2\)
從性質 1 進一步擴展,\(p_2\) 結束的那條返祖邊(\(f_2\) 結尾)一定是從 \(s_1\) 的某個后代發出的,而 \(p_1\) 先生成所有這條返祖邊還沒被用,於是他不可能比 \(f_1\) 還得,就有了 \(f_1\le f_2\)

性質 3:對於兩條起點終點相同的路徑 \(p_1:s\Rightarrow f,p_2:s\Rightarrow f\),設 \(v_1,v_2\) 分別是兩條路徑上的第二個點,若 \(p_1\)\(p_2\) 之前被生成,且 \(v_1\neq f,low2(v_1)<s\),則有 \(v_2\neq f\) 以及 \(low2(v_2)<s\)
由於產生順序,臨界表中 \(v_2\) 被排序在了 \(v_1\) 的后面,而 \(low(v_1)=low(v_2)=f\),則可以得知 \(v_2\neq f\) 以及 \(low2(v_2)<s\)
這個性質在一定程度上體現了引入 \(low2\) 的必要性

Embedding the Path

按照上面方法找到的若干條路徑,顯然每條路徑必定處於同一個 Segment 中
一個 Segment 包含的所有路徑一定是被連續生成的,且 Segment 的被發現順序按照 \(u_i\) 從大到小(考慮上面的圖)
考慮加入一個新 Segment \(S\) 時,環 \(C\) 和其他在他之前發現的 Segment 都已經被嵌入,檢查其第一條路徑是否可以嵌入,若可以,再遞歸判斷剩下的

之前說過一個 Segment 必定全部被嵌入到環 \(C\) 的同一側,后面描述某由 \(u_i\) 的一個兒子 \(v\) 的子樹中的所有邊組成的 Segment \(S\) 被嵌入到了環 \(C\)左邊,意思是圍繞 \(u_i\) 的點按照順時針分別是 \((u_{i-1},u_i),(u_i,v),(u_i,u_{i+1})\)
描述某 Segment \(S\) 被嵌入到了環 \(C\)右邊,意思是圍繞 \(u_i\) 的點按照順時針分別是 \((u_{i-1},u_i),(u_i,u_{i+1}),(u_i,v)\)
(再次說明想象一顆搜索樹的時候讓根在下面)

有以下定理

考慮某條划分出的路徑 \(p:u_i\Rightarrow u_j\),他可以被嵌入到環的左邊(右邊)當且僅當不存在一條返祖邊 \((x,u_k)\) 在此之前被嵌入到了環的左邊(右邊),且滿足\(v_j<v_k<v_i\)
簡單證明:
若不存在滿足條件的返祖邊,那么只要把 \(p\) 和環 \(C\) 貼的足夠近,就一定可以嵌入而不影響其他部分
若存在返祖邊 \((x,u_k)\),可能有 \(x\) 就在環上也就是 \(x=u_l\),也可能有 \((x,u_k)\) 在某 Segment \(S'\) 上,此時設 \(S'\) 的第一條邊是 \((u_l,v)\)
由於 \(S'\) 先被發現,考慮生成路徑的順序,有 \(u_l\ge u_i\),下面以往左邊嵌入為例分類討論(下圖中 \(v\) 數組對應文中 \(u\) 數組):

  • \(u_l>u_i\),如圖 (a),考慮從 \(u_j\)\(u_l\) 的樹邊,構成了三條從 \(u_i\)\(u_k\) 的邊,必定相交,違反引理 2
  • \(u_l=u_i\),路徑 \(p_1:u_l\Rightarrow u_m\) 是 Segment \(S'\) 中的第一條路徑,根據之前 Pathfinding 中的性質 3,有 \(u_m\le u_j\)
    • \(x=u_l\),就是返祖邊的起點也在環上,此時根據給出邊的排序方式必定有 \(u_k\le u_j\),矛盾;於是后面不用再考慮這種情況,Segment \(S'\) 至少要有兩條邊,也就是了 \(v\neq u_m\)
    • \(u_m<u_j\),如圖 (b),考慮 \(p:u_i\Rightarrow u_j\) 以及從 \(u_k\)\(u_i\) 的所有樹邊,會產生三條從 \(v_k\)\(v_i\) 的路徑違反引理 2
    • \(u_m=u_j\),如圖 (c),之前說 \(v\)\(p_1\) 中的第二條邊,現在再設 \(p\) 上的第二條邊是 \(y\),那么由於 \(v\neq u_m,low2(v)\le u_k< u_l\),於是現在對 \(p,p_1\) 應用 Pathfinding 中的性質 3,得到 \(y\neq u_j,low2(y)<u_m\)
      更進一步,由於 \(low(y)=v_j\),可以得知 \(low2(y)>v_j\),於是 \(low2(y)\) 的位置就如圖所示了(但 \(low2(y)\)\(u_k\) 的位置關系其實是未確定的)
      於是可以構造出三條從 \(v_k\)\(low2(y)\) 的路徑(一條走 \(p\),一條 \(p_1\),一條他們之間的樹邊)

於是就可以根據以上定理判斷一條路徑能否被嵌入

找到要嵌入的 Segment \(S\) 中的第一條路徑 \(p\),嘗試將 \(p\) 嵌入到環 \(C\) 的左側,檢查所有返祖邊來確定能不能直接將 \(p\) 嵌入;如果不能,把所有擋住了 \(p\) 的返祖邊(也就是邊 \((x,u_k)\))從 \(C\) 的左側轉移到右側,如果這樣搞完產生了其他沖突(某些在右側的邊需要移動到左側)就說明 \(G\) 不是平面圖
否則就遞歸嵌入其他路徑

如何維護?
考慮 \(L\) 按順序存入滿足 \(1\Rightarrow u_k\Rightarrow u_i\),且有返祖邊 \((x,u_k)\) 被嵌入到了環的左邊的 \(u_k\),當然若存在多條這樣的返祖邊,同一個 \(u_k\) 可能在其中出現多次
同理維護 \(R\)

  • 當結束了 \(u_{i+1}\) 的所有 Segment 的嵌入,從 \(L,R\) 中刪去 \(u_i\)
  • \(p:s\Rightarrow f\) 是 Segment \(S\) 的第一條線段,且 \(f\neq 1\),那么嵌入 \(p\) 后將 \(f\) 加入 \(L\)\(R\)
    • \(p\) 能被嵌入到左邊(右邊)當且僅當 \(L(R)\) 中最大元素小於等於 \(f\)
  • 當嵌入產生沖突,需要把 \(L(R)\) 中的一部分點轉移到 \(R(L)\)
    • 當確定了一條返祖邊在左(右)邊后,他要求和他在同一個 Segment 中的所有返祖邊在同一側,同時要求另一些返祖邊在異側。於是定義一個 block 是一個極大的,滿足其中一個的位置(左或右)被確定,剩下的都被確定的集合

發現這個 \(L,R\) 就是棧,第二個操作能用棧做的原因是要插入的話一定是最大的,所以直接放到棧頂

對於一個 block,有如下性質:
對於 block \(B\)\(B\cap L(B\cap R)\)\(L(R)\) 上是連續的一段

基於此性質,可以用 \((x,y)\) 來維護一個 block,分別表示他在 \(L\)\(R\) 中的最小元素
那么嵌入 \(p\) 前先把沖突的交換掉,然后再把那些沖突的 \(u_k\) 的 block 和 \(p\) 的 block 合並起來
可以對過程歸納得到上面的性質

回溯的處理

遞歸下去是簡單的,但當遞歸處理完某個 Segment 時,由於選定環的不同會帶來一些問題
設原來選定的環 \(C\)\(u_1\rightarrow u_2\rightarrow \cdots\rightarrow u_n\rightarrow u_1\),而遞歸進某 Segment 后選定的環 \(C\)\(u_i\rightarrow v\Rightarrow u_j\Rightarrow u_i\)
設維護每個 block 的點對的棧叫做 \(B\)
那么 \(L,G,B\) 中,所有大於等於 \(u_i\) 的部分與原來的 \(C\) 無關,可以刪掉
所有在區間 \((u_j,u_i)\) 中的部分,由於在遞歸進新環時可能被放在了新環的不同側,但此時要求他在原環的同一側(因為處於同一個 Segment 中),那么就要把他往同一側移動並合並 block,移動不了就不是平面圖

實現細節

由於這些合並操作以及如上 block 的性質的存在,\(L,R\) 用鏈表維護更好
用一個棧 \(B\) 來對於每個 block 維護點對 \((x,y)\),若某 block 不存在 \(L(R)\) 中的點,那么 \(x(y)\) 的值就是 \(0\)
\(R\) 中需要加入一些特殊標記來區分原來環 \(C\) 的信息和遞歸下去新的環 \(C\) 的信息


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM