# Cayley's Formula 與 Prüfer Code 這篇要來聊聊生成樹,在競程最常看到的生成樹題目,除了最小生成樹相關的之外,應該就是計數了。最小生成樹在[這一篇](https://hackmd.io/@ShanC/minimum-spanning-tree)聊過,這裡主要就是談談計數。計數就是計算某種東西的數量,本質上就是要能夠和 $\mathbb{N}$ 一一對應 (或 bijection) 而已。國高中的計數就只是算算排列組合數、要分成幾堆之類而已 然而,在樹的計數,因為樹本身的結構很特殊,計數並不是一件簡單的事情。這類關於樹的競程題非常少見,但是每次見到鐵定是難題,尤其那些會跟 Combinatorics 一起出現的怪東西們,更是令人頭痛 這篇筆記會以生成樹作為切入點,來聊聊 Cayley's Formula、Prüfer Code 與克希荷夫的矩陣樹定理,並提供三種證明 Cayley's Formula 的方法 由於有些東西真的太難了,可能不會講要怎麼證明 ||反正競程能用就好|| ## 生成樹 通常我們會討論生成樹,都是在一張一般的圖上討論。如果是樹的話,討論其生成樹沒什麼意義,因為樹的生成樹就是自己 ### 定義 若一棵樹 $T$ 是一張連通圖 $G$ 的子圖,且 $V(T) = V(G)$ (即 $T$ 擁有所有 $G$ 的節點),則稱 $T$ 為一棵生成樹 <center class = "half"> <img src="https://hackmd.io/_uploads/B1NKHX98kl.png" style="width: 340px"> <img src="https://hackmd.io/_uploads/Hy6qrXcLJg.png" style="width: 350px"> </center> <p class="text-center"> 下圖就是上圖的生成樹 </p> ### 常見的生成樹例子 #### 深度優先搜尋樹 DFS Tree [深度優先搜尋 (DFS)](https://hackmd.io/@ShanC/bfs_dfs) 會訪問圖上的所有節點。事實上將走訪路徑保留後,可以連接所有節點形成一顆生成樹 #### 廣度優先搜尋樹 BFS Tree 相同地,BFS 也後產生一顆生成樹。此生成樹會有一個性質 : 根節點所有其他點的距離為最短 #### 最短路徑樹 對於一張帶權圖,若利用 Dijkstra's algorithm,由於一定會遍歷整張圖的所有節點,因此肯定會形成一棵生成樹。而如果將出發點 $s$ 視為根,那麼 $s$ 到所有點的路徑邊權總和最小 (俗稱路徑最短) ## Prüfer Code 上面介紹完生成樹,可以得知一張圖的生成樹可以有很多種,但是具體來說有幾種呢? 既然圖是一種有限結構,那生成樹的數量也應該是有限的吧! 那具體來說是幾種呢? 直接算真的非常困難,所以我們可以先把所有的樹都編成一組 Prüfer Code,說明 Prüfer Code 與生成樹是 bijection。如此一來,算 Prüfer Code 的數量就等於數生成樹的數量。這樣就可以導出一個公式 (Cayley's Formula) 來解決這個問題 備註 : 這裡我們討論的節點都有**數字標籤** ### 演算法 #### 輸入 一棵樹 $T$。其中,節點集合 $S=[n]=\{1, ..., n\}\subseteq \mathbb{N}$ #### 輸出 一個由節點標籤組成的序列 $f(T)=(a_1, a_2, ..., a_{n-2})$。其中,序列長度為 $n - 2$ #### 過程 1. 給一個圖 $T$、維護序列 $f(T)$ 2. 總共迭代 $n-2$ 次 3. 在第 $i$ 次迭代時,把葉子中編號最小節點的鄰居當作 $a_i$,並刪掉葉子中編號最小節點 ### 舉例說明 給一張 $7$ 個節點的樹、$f(T)=()$: <center> <img src="https://hackmd.io/_uploads/BkOv_IW4xg.png" style="margin: 0 auto; display: block; width: 400px"> </center> $~$ 刪除 $2$、$f(T)=(7)$: <center> <img src="https://hackmd.io/_uploads/SylZFLbVxx.png" style="margin: 0 auto; display: block; width: 400px"> </center> $~$ 刪除 $3$、$f(T)=(7, 4)$: <center> <img src="https://hackmd.io/_uploads/rJsHKLbEgl.png" style="margin: 0 auto; display: block; width: 400px"> </center> $~$ 刪除 $5$、$f(T)=(7, 4, 4)$: <center> <img src="https://hackmd.io/_uploads/rJq5YUZVxg.png" style="margin: 0 auto; display: block; width: 400px"> </center> $~$ 刪除 $4$、$f(T)=(7, 4, 4, 1)$: <center> <img src="https://hackmd.io/_uploads/BkgfqL-4eg.png" style="margin: 0 auto; display: block; width: 300px"> </center> $~$ 刪除 $6$、$f(T)=(7, 4, 4, 1, 7)$: <center> <img src="https://hackmd.io/_uploads/By6KcLbNlg.png" style="margin: 0 auto; display: block; width: 250px"> </center> $~$ 刪除 $7$、$f(T)=(7, 4, 4, 1, 7, 1)$: <center> <img src="https://hackmd.io/_uploads/HJ7es8bEge.png" style="margin: 0 auto; display: block; width: 125px"> </center> 刪到只剩 $2$ 個節點就可以停了 輸出 : 序列 $(7, 4, 4, 1, 7, 1)$ 藉由這個演算法,可以知道每棵生成樹都會對應一個序列,接下來你可能會好奇這個序列是否代表唯一的生成樹,事實上答案是肯定的。下一段 Cayley's Formula 的證明中,會證明這件事 ## Cayley's Formula ### 公式 對於具有標籤 $[n]=\{1,...,n\}$ 的節點集合,總共有 $n^{n-2}$ 棵樹 ($n\geq 2$) ### 舉個例子 當 $n=3$ 時,樹的數量為 $3^{3-2}=3$ <center> <img src="https://hackmd.io/_uploads/BkZ368-Ngx.png" style="margin: 0 auto; display: block; width: 500px"> </center> 注意 : 雖然三棵樹是同構 (isomorphism),但因為編號不同,所以要視為三種不同生成樹 ### 證明 首先推一下 Prüfer Code 總共有多少種可能 : 已知 Prüfer Code 長度為 $n - 2$,序列每個位置可以填入 $n$ 種數字標籤,因此共有 $n^{n-2}$ 種可能 <center> <img src="https://hackmd.io/_uploads/HyCnjacExe.png" style="margin: 0 auto; display: block; width: 500px"> </center> $~$ 接下來使用歸納法證明 Prüfer Code 與生成樹是 bijection : 令 $S^{n-2}$ 為序列的集合,$S\subseteq \mathbb{N}$ 是大小為 $n$ 的節點集合 Basis step : 當 $n=2$ 存在一個 $2$ 節點的樹,其序列長度為 $0$,是唯一的空序列 Induction step : 當 $n\gt 2$ 假設給定一個節點集合 $S$ 與序列 $a$,存在一個唯一的 $T$ 使得 $f(T)=a$ 令第一個被刪除的葉節點叫 $x$。根據演算法,我們會紀錄 $a_1$ 在序列中,也就是 $x$ 的唯一鄰居,因此 $T$ 存在一條邊 $xa_1$。在刪除 $x$ 後,樹的節點集合變成 $S'=S-\{x\}$,然後序列 $a'=(a_2, ..., a_n)$ 根據歸納假設,僅存在一棵節點集合為 $S'$ 樹 $T'$ 使得 $f(T')=a'$ 因為每棵序列為 $a$ 的樹都有加上 $xa_1$,所以僅存在最多一個可能使 $f(T)=a$。再者,將 $T'$ 加上 $xa_1$ 會形成節點集合 $S$ 與序列 $a$,所以這就是那唯一的可能 由於樹和 Prüfer Code 是 bijection。Prüfer Code 的數量是 $n^{n-2}$,那麼樹的數量也是 $n^{n-2}$ ## 一些拓展 ### 公式 : 固定 degree 的情況下求有幾棵樹 給定一些整數 $d_1, d_2, ..., d_n$,加起來為 $2n-2$ 總共有 $\cfrac{(n-2)!}{\Pi (d_i-1)!}$ 棵節點集合為 $[n]$ 的樹使每個節點 $i$ 都有度數為 $d_i$ ### 推導 在序列中,每個元素 $x$ 都會出現 $d_x-1$ 次,因為在演算法中我們會把與其相連的葉節點都刪掉,直到 $x$ 成為葉節點或是成為最後兩個的其中一個節點。因此,在長度為 $n-2$ 的序列中,每個元素 $i$ 都出現了 $d_i-1$ 次。當我們隨便亂生一個串,總共會有 $(n-2)!$ 個序列,但其中有重複的,所以要除掉 $\Pi (d_i-1)!$ 次 其實也可以寫成 multinomial coefficient 的形式 $$ \cfrac{(n-2)!}{(d_1-1)!(d_2-1)!... (d_n-1)!}=\dbinom{n-2}{d_1-1, d_2-1, ..., d_n-1} $$ ### 公式 : 求讓圖連通的方法數 給定 $k$ 個連通塊的大小 $s_1, s_2, ..., s_k$,總節點數為 $\sum ^{k}_{i=1}s_i=n$ 讓圖連通的方法數 : $n^{k-2}~\Pi^k_{i=1} s_i$ ### 推導 我不會,但[這篇](https://cp-algorithms.com/graph/pruefer_code.html)有寫 (因為他重複使用變數,而且步驟有點跳,所以我看不懂) ## 另一種推導 Cayley's Formula 的方法 因為最近學了生成函數 (generating function),所以給出用生成函數推導的方法 ### 推導 計算 $n$ 個點上有根樹的數量叫 $t(n)$,若移除了根並觀察子樹,會得到一個遞迴式 ||天啊這要怎麼觀察|| $$ t(n+1)=(n+1)\sum_{k\geq 0}\sum_{i_1+i_2+...+i_k=n, i_j\geq1}\frac{n!}{i_1!i_2!...i_k!} t(i_1)t(i_2)...t(i_k) \frac{1}{k!} $$ 乘上 $x^{n+1}$ (因為我們要搞生成函數),然後整理一下 $$ \frac{t(n+1)}{(n+1)!}x^{n+1}=\sum_{k\geq 0}\frac{1}{k!}\sum_{i_1+i_2+...+i_k=n, i_j\geq1}\frac{t(i_1)x^{i_1}}{i_1!}\frac{t(i_2)x^{i_2}}{i_2!}...\frac{t(i_k)x^{i_k}}{i_k!} $$ 這就會是我們的生成函數 $T(x)$ 囉!! (最下面的等式是用泰勒展開搞回去) $$\begin{split} T(x)&=\sum_{n\geq 0}\frac{t(n+1)}{(n+1)!}x^{n+1}=\sum_{k\geq 0}\frac{1}{k!}\sum_{n\geq 0}\sum_{i_1+i_2+...+i_k=n, i_j\geq1}\frac{t(i_1)x^{i_1}}{i_1!}\frac{t(i_2)x^{i_2}}{i_2!}...\frac{t(i_k)x^{i_k}}{i_k!} \\&=x\sum_{k\geq 0} \frac{T(x)^k}{k!} \\&=xe^{T(x)} \end{split} $$ 接下來把有 $T(x)$ 的都放到左邊 $$ T(x)e^{-T(x)}=x $$ 因為它長的很像拉格朗日反演的樣子,所以我們弄弄看拉格朗日反演公式 然後再平移一下多項式 $$\begin{split} [x^n]T(x)&=\cfrac{1}{n}[x^{-1}]\cfrac{1}{(xe^{-x})^n} \\&=\cfrac{1}{n}[x^{-1}]x^{-n}e^{nx} \\&=\cfrac{1}{n}[x^{n-1}]e^{nx} \\&=\cfrac{1}{n}\cfrac{n^{n-1}}{(n-1)!} \\&=\cfrac{n^{n-1}}{n!} \end{split} $$ 因此,$$t(n)=n^{n-1}$$ 最後,因為我們算的是有根的樹,但答案應該要是沒有根的樹,因此要除掉一個 $n$ 得到 $n^{n-2}$ 為有標籤的節點所能形成的樹的數量 ## 克希荷夫矩陣樹定理 Kirchhoff's Matrix Tree Theorem 克希荷夫的矩陣樹定理可以求出給定一張圖 $G$ 的生成樹數量。若要理解其方法,需要先知道要怎麼用矩陣玩圖論。這種用線性代數玩圖論的領域叫做 Spectual Graph Theory 首先,這裡的圖都假設連通,否則沒辦法討論其生成樹 ### 鄰接矩陣 Adjancency Matrix 這應該資料結構就學過了,放在數學裡也是一樣 鄰接矩陣 $A\in \mathbb{R}^{N\times N}$ 是一個方陣。對於每個 $A_{i, j}$ 代表點對 $(i, j)$ 之間的邊數,其中有幾種性質 - 允許自環,每個自環會在對角線上的元素貢獻 $2$ - 鄰接矩陣在無向圖是對稱的矩陣 ### 度數矩陣 Degree Matrix 度數矩陣 $D\in\mathbb{R}^{N\times N}$ 是一個對角矩陣。對於每個節點 $i$,$D_{i, i}$ 代表其度數,除了對角以外的部分皆為 $0$。其中,自環對度數貢獻為 $2$ ### 拉普拉斯矩陣 Laplacian Matrix 拉普拉斯矩陣 $$L=D-A$$ 有學過向量微積分的話應該很熟悉拉普拉斯運算子,就是梯度的散度那個,它本質上就是相鄰減自身,通通加總,並除掉一個分母。拉普拉斯矩陣也有相似的概念,只是不知道為什麼反過來了 ### 餘因式 Minor 令 $B$ 為一個方陣,$B$ 的 minor $M_{i, j}$ 是一個消除第 $i$ 列第 $j$ 行後的矩陣的行列式 ### 餘因子 Cofactor 在上一個定義中,$B$ 的 cofactor 為 $$C_{i, j}=(-1)^{i+j}M_{i, j}$$ ### 引理 1 令 $L$ 為某張無向圖的拉普拉斯矩陣,則所有 $L$ 的 minor 套上絕對值後都相同 ### 引理 2 令 $L$ 為某張無向圖的拉普拉斯矩陣,則所有 $L$ 的 cofactor 都相同 ### 邊收縮 Contraction 如下圖,收縮後的圖 $G.e$ <center> <img src="https://hackmd.io/_uploads/SyF5TFoExx.png" style="margin: 0 auto; display: block; width: 300px"> </center> ### 矩陣樹定理 Matrix Tree Theorem 給定一張無向圖 $G=(V, E)$,對於任何節點 $i, j\in\{1, 2, ..., |V|\}$,$G$ 的生成樹數量為 $\tau(G)=C_{i, j}$ ### 證明概述 證明有很多版本,這裡採用我比較看得懂的版本,因為太複雜所以大概說一下就好 ||可能有點不太嚴謹|| 因為圖都是連通的,考慮一條邊 $e$,當我們在找生成樹的時候,$e$ 要嘛在樹上要嘛不在 (廢話)。若 $e$ 在樹上,則我們不用考慮他,可以使用邊收縮並找出 $G.e$ 的生成樹數量。若 $e$ 不在樹上,相當於我們忽略它,因此就是要找 $G-e$ 的生成樹數量。因此,可以得到 $\tau(G)=\tau(G-e)+\tau(G.e)$ ||有點像是對圖做遞迴的感覺|| <center> <img src="https://hackmd.io/_uploads/BJEgQcoVxx.png" style="margin: 0 auto; display: block; width: 300px"> </center> $~$ 我們可以對邊做歸納法 Basis case : 整張圖只有兩點與他們之間的 $d$ 條邊 $L=\left( \begin{array}{cc} d & -d \\ -d & d \\ \end{array} \right)$,所以 $\tau(G)=C_{1, 1}=L_{1, 1} = d$ 歸納假設 : 假設對 $G-e$ 與 $G.e$,定理都為真 Inductive step : 我們希望證明定理在 $\tau(G)$ 時為真 將兩節點 $i, j$ 特別挑出來,令 $d_i, d_j$ 為度數,$d$ 為 $i, j$ 之間的邊數,則我們可以整理出以下行列式。其中,$r_i$ 與 $r_j$ 是紀錄 $i, j$ 的相關訊息,$L'$ 是拉普拉斯矩陣中沒動到的其他部分 $$ det(L^G)=\left| \begin{array}{ccc} d_i & -d & r_i^T \\ -d & d_j & r_j^T\\ r_i & r_j & L' \\ \end{array} \right| $$ 當然我們也可以整理出 $G-e$ 的行列式 $$ det(L^{G-e})=\left| \begin{array}{ccc} d_i - 1 & -d + 1 & r_i^T \\ -d + 1 & d_j - 1 & r_j^T\\ r_i & r_j & L' \\ \end{array} \right| $$ 還有 $G.e$ 的行列式 $$ det(L^{G.e})=\left| \begin{array}{cc} d_i+d_j-2 & r_i^T+r_j^T \\ r_i+r_j & L' \\ \end{array} \right| $$ 根據引理 1, 2,取 $i, i$ 也會是答案。為了結束歸納法,我們說明 $$ det(L^G_{i, i})=det(L_{i, i}^{G-e})+det(L^{G.e}_{i, i}) $$ 也就是 $$ \left| \begin{array}{cc} d_j & r_j^T\\ r_j & L' \\ \end{array} \right|=\left| \begin{array}{cc} d_j - 1 & r_j^T\\ r_j & L' \\ \end{array} \right|+\left|\begin{array}{cc} L' \end{array} \right| $$ 這可以用 Laplace expansion 展開來證 最後,根據歸納假設,因為定理在 $G-e$ 與 $G.e$ 為真,因此在 $G$ 也為真 所以 $$C^G_{i, i}=C^{G-e}_{i, i}+C^{G.e}_{i, i}=\tau(G-e)+\tau(G.e)=\tau(G)$$ ### 舉例說明 下圖總共有八種生成樹 <center> <img src="https://hackmd.io/_uploads/r1ytg6jEex.png" style="margin: 0 auto; display: block; width: 200px"> </center> $~$ 當然我們也可以用矩陣樹定理算出來 $$ A=\left( \begin{array}{cccc} 0 & 1 & 1 & 0\\ 1 & 0 & 1 & 1\\ 1 & 1 & 0 & 1\\ 0 & 1 & 1 & 0\\ \end{array} \right),~ D=\left( \begin{array}{cccc} 2 & 0 & 0 & 0\\ 0 & 3 & 0 & 0\\ 0 & 0 & 3 & 0\\ 0 & 0 & 0 & 2\\ \end{array} \right), ~L=\left( \begin{array}{cccc} 2 & -1 & -1 & 0\\ -1 & 3 & -1 & -1\\ -1 & -1 & 3 & -1\\ 0 & -1 & -1 & 2\\ \end{array} \right) $$ 將第 $2$ 行第 $2$ 列刪掉得到 $L_{2, 2}=\left( \begin{array}{ccc} 2 & -1 & 0\\ -1 & 3 & -1\\ 0 & -1 & 2\\ \end{array} \right)$ $$ \begin{split} det(L')&=\left| \begin{array}{ccc} 2 & -1 & 0\\ -1 & 3 & -1\\ 0 & -1 & 2\\ \end{array} \right| =2\left| \begin{array}{ccc} 3 & -1\\ -1 & 2\\ \end{array} \right|+\left| \begin{array}{ccc} -1 & -1\\ 0 & 2\\ \end{array} \right| =2\times 5 - 2 =8 \end{split} $$ ### 導出 Cayley's Formula Cayley's Formula 的條件與矩陣樹定理的條件有點不同 - Cayley's Formula : 有標籤的節點集合 - 矩陣樹定理 : 一張圖 $G$ 若把矩陣樹定理給的 $G$ 換成完全圖 $K_n$,那就相當於變成 Cayley's Formula 的條件,所以就可以計算拉普拉斯矩陣 $$ D^{K_n}=\left( \begin{array}{cc} n & n & \dots & n\\ n & n & \dots & n\\ \vdots & \vdots & \ddots & \vdots\\ n & n & \dots & n \end{array} \right) ,~A^{K_n}=\left( \begin{array}{cc} 1 & 1 & \dots & 1\\ 1 & 1 & \dots & 1\\ \vdots & \vdots & \ddots & \vdots\\ 1 & 1 & \dots & 1 \end{array} \right) $$ $$ L^{K_n}=D^{K_n}-A^{K_n}=\left( \begin{array}{cc} n-1 & -1 & \dots & -1\\ n & n-1 & \dots & -1\\ \vdots & \vdots & \ddots & \vdots\\ -1 & -1 & \dots & n-1 \end{array} \right) $$ 然後再找出 cofactor $C_{i, j}$ (刪哪行哪列都一樣),其中 cofactor 的大小只有 $(n-1)\times(n-1)$ $$ C^{K_n}_{i, j}=\left| \begin{array}{cc} n-1 & -1 & \dots & -1\\ -1 & n-1 & \dots & -1\\ \vdots & \vdots & \ddots & \vdots\\ -1 & -1 & \dots & n-1 \end{array} \right| $$ 這個鬼東西並不好求,所以可以考慮找 eigenvalue。其中,我們需要用到以下性質 : - 矩陣行列式就是所有 eigenvalue 相乘 - 矩陣的 trace 是其 eigenvalue 之和 - 若 $\lambda$ 是矩陣 $A$ 的 eigenvalue,則 $\lambda + c$ 是 $A + cI$ 的 eigenvalue 令 $L^i$ 是這個 $(n-1)\times (n-1)$ 矩陣,考慮 $L^{i}-nI$ 是一個所有元素都是 $-1$ 的矩陣 - 觀察 trace 會等於 $(-1)\times (n-1)=1-n$ 又等於所有 eigenvalue 之合 - 所以可以得到 $L^{i}-nI$ 的所有 eigenvalue 中只有一個是 $1-n$,其他都是 $0$ - 因此所有的 eigenvalue 就是剛才的結果加 $n$,也就是 $1, n, ..., n$,共 $n-2$ 個 $n$ 與 $1$ 個 $1$ - 將它們所有 eigenvalue 乘起來就會是行列式的答案,也就是 $n^{n-2}$ 答案就這樣莫名其妙地算出來了 ## 備註 這些東西一出現就肯定是難題,通常跟什麼 generating function、stirling numbers 等等噁心的東西一起出現,所以建議去學 Combinatorics 或是讀 Generatingfunctionology (一本書) ## 題目練習 [Zerojudge g088. 生成樹數量](https://zerojudge.tw/ShowProblem?problemid=g088) (奇怪的東西) [OnlineJudge 10843 - Anne's game](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=20&page=show_problem&problem=1784) (Cayley's formula 裸題) [Codeforces 156 D. Clues](http://codeforces.com/contest/156/problem/D) (拓展 Cayley's formula) [CSES Prüfer Code](https://cses.fi/problemset/task/1134/) (Prüfer Code 裸題) [Codeforces 917 D. Stranger Trees](https://codeforces.com/problemset/problem/917/D?locale=en) (做法很多,要想一下) [Codeforces 1762 E. Tree Sum](https://codeforces.com/problemset/problem/1762/E) (動動腦) [CSES Functional Graph Distribution](https://cses.fi/problemset/task/2415) (Cayley's formula,好像也要用 Stirling number,神奇的數學題) [ABC 253 Ex - We Love Forest](https://atcoder.jp/contests/abc253/tasks/abc253_h) (矩陣樹定理 + 位元 DP) [ABC 323 G - Inversion of Tree](https://atcoder.jp/contests/abc323/tasks/abc323_g) (矩陣樹) [Atcoder jsc2021 G - Spanning Tree](https://atcoder.jp/contests/jsc2021/tasks/jsc2021_g) (矩陣樹) ---- ## 參考資料 - D.B.West - Introduction to Graph Theory 2/e - [CP-algorithms - Prüfer code](https://cp-algorithms.com/graph/pruefer_code.html) - [Geeksforgeeks - Cayley's Formula](https://www.geeksforgeeks.org/cayleys-formula/) - [[Tutorial] Generating Functions in Competitive Programming (Part 2)](https://codeforces.com/blog/entry/77551) - [師大演算法筆記 - graph spectrum](https://web.ntnu.edu.tw/~algo/GraphSpectrum.html) ---- > [ShanC 程式競賽筆記](https://hackmd.io/@ShanC/B1ouGxqcC) > 作者: ShanC > 更新: 2025/6/25