Prufer序列學習筆記
\[\Large \rm Prufer~序列的定義 \]
\(\quad\rm Prufer\) 序列可以將一顆結點數為 \(n\) 的有標號無根樹用一個長度為 \(n-2\),值域為 \([1,n]\) 的數列唯一表示,即有標號無根樹和 \(\rm Prufer\) 序列呈雙射關係。
\(\quad\)具體來說,有標號無根樹的構建方式如下 :
- 選擇一個編號最小的葉子節點,並將其刪除。
- 將這個葉子節點所連線的點的編號加入 \(\rm Prufer\) 序列中。
- 重複以上步驟 \(n-2\) 次,直到樹上只剩下 \(2\) 個點。
\(\quad\)這是某一顆點數為 \(n\) 的有標號無根樹的 \(\rm Prufer\)
\[\Large \rm Prufer~序列的求法 \]
\(\quad\)由其過程,顯然有一個使用堆優化的 \(\Theta(n\log n)\) 做法,但 \(\rm Prufer\) 序列其實可以線性構造。
\(\quad\)記錄所有點的度數和一個指標 \(p\) 指向編號最小的葉子節點,進行以下操作 :
- 將 \(p\) 指向的結點刪除,檢查是否出現了新的葉結點。
- 如果產生了新的葉結點,記其編號為 \(x.\) 若 \(x>p\),則不做任何操作,否則將其刪除,並檢查刪除 \(x\) 以後是否出現了新的葉結點,重複這一步操作直到沒有產生新的葉結點或新產生的結點編號大於 \(p.\)
- 讓 \(p\) 自增直到遇見下一個葉結點為止。
- 重複以上操作直到結點數為 \(2\) 可以得到這棵樹的 \(\rm Prufer\) 序列。
\(\quad\)可以發現,在演算法流程中,每條邊只在其連線的外層結點被刪除時被遍歷過一次,並且 \(p\) 單調遞增,樹中的節點數單調遞減,所以每個點也只被遍歷過一次。
\(\quad\)總時間複雜度 \(\Theta(n).\)
\[\Large \rm Prufer~序列還原有標號無根樹 \]
\(\quad\)顯然還是有一個堆優化的 \(\Theta(n\log n)\) 做法。
\(\quad\)從前到後列舉 \(\rm Prufer\) 序列中的每一個數,維護不在序列中的結點編號的最小值。顯然不在序列中的是葉子節點,並且其最小值為最後一個加入的,於是將其與當前列舉的序列中的數連邊。連邊後若序列中已沒有列舉的這個數,那麼將其踢出序列作為新的葉子結點。
\(\quad\)考慮以與之前構造 \(\rm Prufer\) 序列相同的方法構造線性做法。
\(\quad\)記一個指標 \(p\) 指向不在序列中的最小結點,如果將其連向序列中列舉的位置,並將列舉的位置刪除。序列中沒有這個結點了,那麼如果被刪除的結點比 \(p\) 小,直接將其與現在序列中列舉的數連邊後將其刪除,重複操作。如果這個結點的值大於 \(p\),那麼不用管它,在後面它一定會被列舉到。
\(\quad\)顯然,這種演算法的時間複雜度為 \(\Theta(n).\)
\[\Large \rm Prufer~序列的應用 \]
\(\large \rm Cayley~公式\)
\(\quad\)完全圖 \(K_n\) 有 \(n^{n-2}\) 顆生成樹。
\(\quad\)證明方法很多,其中最簡單的應該是利用 \(\rm Prufer\) 序列。
\(\quad\)考慮到任何一個長度為 \(n-2\) 的 \(\rm Prufer\) 序列唯一對應一顆大小為 \(n\) 的有標號無根樹,於是考慮計算長度為 \(n-2\) 的 \(\rm Prufer\) 序列的數量,又因為其值域為 \([1,n]\),故總方案數為 \(n^{n-2}.\)
\(\large \rm 限定度數的有標號無根樹計數\)
\(\quad\)求有 \(n\) 個結點,且第 \(i\) 個結點的度數為 \(d_i\) 的有標號無根樹的數量。
\(\quad\)考慮到一個點的度數為其在 \(\rm Prufer\) 序列中出現次數 \(+1\),於是對於一個度數為 \(d_i\) 的點,其在 \(\rm Prufer\) 序列中的出現次數應為 \(d_i-1\),故存在這樣的有標號無根樹當且僅當 \(\sum_{i=1}^n d_i-1=n-2\),並且這樣的樹的數量為 :
\[\dbinom{n-2}{d_1-1,d_2-1,\cdots ,d_n-1}=\frac{(n-2)!}{(d_1-1)!(d_2-1)!\cdots (d_n-1)!} \]