矩阵树定理

矩阵树定理,又称 Matrix-Tree 定理,是用于解决图上生成树问题的有力工具。其基础是基于线性代数中的矩阵和行列式进行计算。

1 基本定义

1.1 图的关联矩阵

我们先来研究无向图的情况。设一张无向图 \(G=(V,E)\)\(|V|=n,|E|=m\),我们给每一条边随意定一个方向,然后定义该图的关联矩阵 \(M\) 为:

\[M_{i,j}=\begin{cases} 1& e_j 是 v_i 的入边\\ -1& e_j 是 v_i 的出边\\ 0& \text{otherwise.}\\ \end{cases} \]

显然该矩阵大小为 \(n\times m\)

1.2 拉普拉斯矩阵

定义一张图的拉普拉斯矩阵(又称基尔霍夫矩阵)\(L_{i,j}\) 为:

\[L_{i,j}=\begin{cases} \text{deg}(v_i)& i=j\\ -\text{cnt}(i,j)& i\ne j \end{cases} \]

其中 \(\text{deg}(v)\) 表示顶点度数,\(\text{cnt}(i,j)\) 表示两点间连边数量(不分方向)。

关于这两个矩阵有一个非常实用的性质:\(L=MM^T\),证明如下:

  • \(L_{i,i}=\sum\limits_{j=1}^m M_{i,j}M_{j,i}^{T}=\sum\limits_{j=1}^mM_{i,j}^2=\text{deg}(i)\)
  • \(L_{i,j}=\sum\limits_{k=1}^m M_{i,k}M_{k,j}^{T}=\sum\limits_{j=1}^mM_{i,k}M_{j,k}=-\text{cnt}(i,j)\)

这将会在下文中用到。

2 基本理论

在正式讲解矩阵树定理前,我们需要说明两个基本理论。

2.1 用关联矩阵刻画生成树

我们最后要求出一棵生成树,相当于在关联矩阵中选出 \(n-1\) 列。设这些列编号集合为 \(S\),记只保留这些列的矩阵为 \(M[S]\)。此时其大小为 \(n\times(n-1)\),不是很美观。考虑把其中任意一行去掉,这样做的含义实际上是忽略生成树的根,因为无向图生成树不需要管根,所以矩阵依然对应唯一的生成树。记去掉任意一行后的矩阵为 \(M_0\),则最后生成树对应的矩阵是 \(M_0[S]\)

考虑此时矩阵 \(M_0[S]\) 要满足什么条件。显然如果生成的树不合法则说明出现了环,而环上的边对应的列向量必然线性相关,那么也就是说 \(M_0[S]\) 不满秩,也就是 \(\text{det}(M_0[S])=0\);反之,我们考虑消元法计算行列式值,每次找出叶子节点所在行,此时这一行上只有一个非零元素,利用该行进行消元,然后删去叶子节点递归进行该过程,最后每一行上都只剩下一个非零元素,所以 \(\text{det}(M_0[S])=\pm 1\)

2.2 柯西-比内定理

柯西-比内定理,又称 Cauchy-Binet 定理,是用于计算两矩阵相乘后行列式结果的定理。令 \(A\)\(n\times m\) 的矩阵,\(B\)\(m\times n\) 的矩阵,则:

\[\text{det}(AB)=\sum_{S\subseteq\{1,2,\cdots,m\}\land |S|=n} \text{det}(A[S])\text{det}(B[S]) \]

3 矩阵树定理

3.1 无向图上的情况

3.1.1 定理内容

\(L_0\)\(L\) 去掉任意的第 \(k\) 行和第 \(k\) 列所得到的矩阵,则该无向图生成树个数为 \(\det(L_0)\)

3.1.2 定理证明

利用上面讲解的基本理论,这个定理的证明其实很简单:

\[\begin{aligned} \det(L_0)&= \det(M_0M_0^{T})\\ &=\sum_{S\subseteq\{1,2,\cdots,m\}\land |S|=n-1} \det(M_0[S])\det(M_0^T[S])\\ &=\sum_{S\subseteq\{1,2,\cdots,m\}\land |S|=n-1} \det(M_0[S])^2\\ \end{aligned} \]

此时 \(S\) 对应一种选边方案,根据上面的说明,只有在该选边方案合法时 \(\det(M_0[S])=\pm 1\),那么 \(\det(M_0[S])^2=1\),也就算出了生成树的个数。

3.2 有向图上的情况

3.2.1 定理内容

对于有向图,我们的生成树实际上有两种:根向生成树和叶向生成树。这里只讨论叶向生成树的方案数,另一种是类似的。

重新定义拉普拉斯矩阵为:

\[L_{i,j}=\begin{cases} \text{deg}_{\text{in}}(v_i)& i=j\\ -\text{cnt}(v_i\to v_j)& i\ne j \end{cases} \]

其中 \(\text{deg}_{\text{in}}(v)\) 表示顶点入度,\(\text{cnt}(i\to j)\) 表示 \(i\)\(j\) 边的个数。

那么此时有向图上的矩阵树定理和无向图基本一致,记 \(L_0\)\(L\) 去掉任意的第 \(k\) 行和第 \(k\) 列所得到的矩阵,则以 \(k\) 为根的叶向生成树个数为 \(\det(L_0)\)

3.2.2 定理证明

此时我们没有 \(L=MM^T\) 了,所以我们需要换一种方法证明。

依然先考虑对 \(M_0[S]\) 消元求行列式,同样从叶子节点开始消元,此时叶子节点对应行上只有一个元素是 \(1\),并且这一列上也只有另一个元素是 \(-1\),所以消完之后每一行会正好剩一个 \(1\),也就是 \(\det(M_0[S])=1\)

但是此时我们只保证了生成出来的是一棵树,并没有保证它是叶向树,考虑用另一个 \(D\) 矩阵强制确定一下,叶向树的另一个条件是除根以外每一个节点都只有一条入边,所以假如我们可以让 \(\det(D_0[S])=1\) 等价于这个条件,就可以满足外向树限制。事实上这也是容易构造的,有:

\[D_{i,j}=\begin{cases} 1& e_j 是 v_i 的入边\\ 0& \text{otherwise.} \end{cases} \]

那么此时我们可以得到 \(L=MD^T\),然后再按照上面的证明方法证即可。

3.3 有边权的情况

有边权其实也比较简单,我们可以将边权 \(w\) 看成 \(w\) 条边,然后跑一下矩阵树。那么根据乘法原理,一棵生成树会被计算其边权的乘积次。所以对于有边权的图跑矩阵树定理,求出来的是所有生成树的边权乘积之和。

4 例题

使用矩阵树的时候常常有一个问题:题目要求边权和,但是矩阵树求的是边权乘积。对此我们也有一些常见的处理方式,下面两道题都会运用。

例 1 LOJ6271 「长乐集训 2017 Day10」生成树求和 加强版

\(\text{Link}\)

首先我们看到要对生成树权值求和,自然想到利用矩阵树定理进行求解。但是矩阵树定理适用于求边权之积的和的情况,与此题并不是很适配。考虑先进行一些转化。

我们发现一棵树的权值就是三进制不进位加法,首先由于不进位我们可以把每一位拆开考虑;而不进位加法则容易让我们想到 \(k\) 维 FWT。在本题中显然 \(k=3\),套用 \(3\) 维 FWT 不进位加法的做法,矩阵是 \(\begin{bmatrix}1&1&1\\1&\omega_3^1&\omega_3^2\\1&\omega_3^2&\omega_3^4\end{bmatrix}\),对于 \(i=0,1,2\) 求出边权 FWT 后的结果,则乘积就是答案 FWT 后结果。如此树的权值就被转化为了乘积,可以直接利用矩阵树定理求解。最后我们对答案做一次 IFWT 即可得出每种权值的树有多少种,累加答案即可。复杂度 \(O(n^3\log_3 V)\)

例 2 P6624 [省选联考 2020 A 卷] 作业题

\(\text{Link}\)

首先看到题目中的 \(\gcd\),想到欧拉反演:

\[\begin{aligned} ans=& \left(\sum w_{e_i} \right)\times \gcd(w_{e_i})\\ =& \left(\sum w_{e_i} \right)\times \sum_{d\mid w_{e_i}} \varphi(d)\\ =& \sum_{d=1}^{w} \varphi(d) \times \sum_{d\mid w_{e_i}} w_{e_i} \end{aligned} \]

所以我们枚举一下 \(\gcd\),然后保留所有是 \(d\) 倍数的边,求出所有生成树边权和的和即可。这容易让我们联想到矩阵树定理,不过矩阵树定理求解的是生成树边权积之和,我们需要一些转化。最简单的想法是把边权放到指数上,构造 \(x^{w_i}\),不过这样的话难以操作且复杂度过高。我们采用另一种方法,把边权记为 \(w_ix+1\),这样我们只需要求出乘积的一次项系数就是边权和了。

那么这样的话我们做乘除法操作的时候就不用管二次项了,于是有如下运算规则:

  • \((a+bx)(c+dx)=ac+(bc+ad)x\)
  • \(\dfrac{1}{a+bx}=\dfrac{b}{a}-\dfrac{b}{a^2} x\)

构造出矩阵后直接高斯消元求解行列式即可,复杂度是 \(O(n^3 V)\) 的。直接跑比较紧张,我们可以用一点优化,显然只有 \(d\) 的倍数出现了至少 \(n-1\) 次时我们才需要求解,那么总的因子个数是 \(\sum \sigma_0(w_i)\),所以我们至多跑 \(\tfrac{\sum \sigma_0(w_i)}{n-1}\) 次,复杂度应该是 \(O(n^2\sum \sigma_0(w_i))\) 的,上界是一个 \(O(n^4\sqrt V)\),可以通过。

posted @ 2025-05-20 09:47  UKE_Automation  阅读(155)  评论(0)    收藏  举报