1. 程式人生 > 其它 >Java基礎——LinkedList集合的特有功能

Java基礎——LinkedList集合的特有功能

一棵大小為 \(n\) 的有標號無根樹對應一個長度為 \(n-2\) 值域為 \([1,n]\) 的 Prufer 序列。

故有 Cayley 公式:\(n\) 個點的完全無向圖的生成樹有 \(n^{n-2}\) 種。

然後是轉換:

樹到序列

  1. 找到當前樹中編號最小的葉子節點,將其父親節點編號加入序列,並刪除該節點。
  2. 如果父親節點度數變為 \(1\),將父親節點當作葉子節點加入待刪佇列。
  3. 重複 1 2 操作直到原樹只剩下兩個點。

注意到最後 \(n\) 節點一定會保留下來,所以對於無根樹的父親節點可以以 \(n\) 為根做一遍 dfs 得到。

於是顯然可以 \(O(n\log n)\) 做。

線性做法是利用了每次刪節點最多隻會新增一個葉子節點的性質,維護一個指標指向下一個要刪的葉子節點。
每次刪掉節點後看父親節點是否變成葉子節點,如果父親變成了編號小於指標的葉子,那麼直接把父親當作下一個葉子,但指標不動;否則就讓指標自增到下一個葉子。

這樣指標只會掃一遍,所有邊只會遍歷一遍,所以是 \(O(n)\)

序列到樹

根據樹到序列的構造,我們發現每個度數為 \(d\) 的節點都在 Prufer 序列中出現了 \(d-1\) 次。

同樣的,我們可以利用這個性質實現序列到樹。

  1. 找到序列中沒有出現過的點(葉子節點)中編號最小的,序列第 \(i\) 項即為其父親,然後刪除該葉子節點。
  2. 如果父親節點度數變為 \(1\)
    ,將父親節點當作葉子節點加入待刪佇列。
  3. 每次 \(i\) 增加並重復 1 2 操作直到序列結束,此時待刪序列中有兩個點,將編號小的父親令為 \(n\)(也就是另一個編號大的)。

同樣有顯然的 \(O(n\log n)\) 做法。

線性做法是一樣。


Prufer 序列通常與有度數限制的計樹有關,會用到組合數學。

P6086 【模板】Prufer 序列

[HNOI2004]樹的計數

[HNOI2008]明明的煩惱

CF156D Clues