矩阵树定理

用途

矩阵树一般用于生成树计数的问题,比如求一个无向图中生成树的个数。用矩阵树定理能极大地降低时间复杂度。

前置知识:行列式

此部分可粗略浏览,了解即可。

对于一个一阶行列式,可写作
d e t ( a 1 , 1 ) = a 1 , 1 det \left( \begin{matrix} a_{1,1} \end{matrix} \right)=a_{1,1} det(a1,1)=a1,1

对于一个二阶行列式,可写作
d e t ( a 1 , 1 a 1 , 2 a 2 , 1 a 2 , 2 ) = a 1 , 1 a 2 , 2 − a 1 , 2 a 2 , 1 det \left( \begin{matrix} a_{1,1} & a_{1,2}\\ a_{2,1} & a_{2,2} \end{matrix} \right)=a_{1,1}a_{2,2}-a{1,2}a_{2,1} det(a1,1a2,1a1,2a2,2)=a1,1a2,2a1,2a2,1

对于一个三阶的行列式,可写作
d e t ( a 1 , 1 a 1 , 2 a 1 , 3 a 2 , 1 a 2 , 2 a 2 , 3 a 3 , 1 a 3 , 2 a 3 , 3 ) = a 1 , 1 a 2 , 2 a 3 , 3 + a 1 , 2 a 2 , 3 a 3 , 1 + a 1 , 3 a 2 , 1 a 3 , 2 − a 1 , 3 a 2 , 2 a 3 , 1 − a 1 , 2 a 2 , 1 a 3 , 3 − a 1 , 1 a 2 , 3 a 3 , 2 det \left( \begin{matrix} a_{1,1} & a_{1,2} & a_{1,3}\\ a_{2,1} & a_{2,2} & a_{2,3}\\ a_{3,1} & a_{3,2} & a_{3,3} \end{matrix} \right)=a_{1,1}a_{2,2}a_{3,3}+a_{1,2}a_{2,3}a_{3,1}+a_{1,3}a_{2,1}a_{3,2}\\ \qquad\qquad \qquad \qquad\qquad\qquad-a_{1,3}a_{2,2}a_{3,1}-a_{1,2}a_{2,1}a_{3,3}-a_{1,1}a_{2,3}a_{3,2} det a1,1a2,1a3,1a1,2a2,2a3,2a1,3a2,3a3,3 =a1,1a2,2a3,3+a1,2a2,3a3,1+a1,3a2,1a3,2a1,3a2,2a3,1a1,2a2,1a3,3a1,1a2,3a3,2

通过观察,我们得到 n n n阶行列式的一般定义。

p 1 , p 2 , … , p n p_1,p_2,\dots,p_n p1,p2,,pn表示一个 1 1 1 n n n的排列。若一个排列的逆序对数个数为偶数,则称这个排列为偶排列;若一个排列的逆序对数个数为奇数,则称这个排列为奇排列。


t ( p 1 , p 2 , … , p n ) = { 0 , 当 p 1 , p 2 , … , p n 是偶排列时 1 , 当 p 1 , p 2 , … , p n 是奇排列时 t(p_1,p_2,\dots,p_n)= \begin{cases} 0,&当p_1,p_2,\dots,p_n是偶排列时\\ 1,&当p_1,p_2,\dots,p_n是奇排列时 \end{cases} t(p1,p2,,pn)={0,1,p1,p2,,pn是偶排列时p1,p2,,pn是奇排列时

n n n阶行列式可以写成
d e t ( a 1 , 1 a 1 , 2 ⋯ a 1 , n a 2 , 1 a 2 , 2 ⋯ a 2 , n ⋮ ⋮ ⋱ ⋮ a n , 1 a n , 2 ⋯ a n , n ) = ∑ p 1 , p 2 , … p n ( − 1 ) t ( p 1 , p 2 , … , p n ) a 1 , p 1 a 2 , p 2 ⋯ a n , p n det \left( \begin{matrix} a_{1,1} & a_{1,2} & \cdots & a_{1,n}\\ a_{2,1} & a_{2,2} & \cdots & a_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ a_{n,1} & a_{n,2} & \cdots & a_{n,n} \end{matrix} \right) =\sum\limits_{p_1,p_2,\dots p_n}(-1)^{t(p_1,p_2,\dots,p_n)}a_{1,p_1}a_{2,p_2}\cdots a_{n,p_n} det a1,1a2,1an,1a1,2a2,2an,2a1,na2,nan,n =p1,p2,pn(1)t(p1,p2,,pn)a1,p1a2,p2an,pn

行列式也可写作
d e t A = d e t ( a 1 , 1 a 1 , 2 ⋯ a 1 , n a 2 , 1 a 2 , 2 ⋯ a 2 , n ⋮ ⋮ ⋱ ⋮ a n , 1 a n , 2 ⋯ a n , n ) = ∣ a 1 , 1 a 1 , 2 ⋯ a 1 , n a 2 , 1 a 2 , 2 ⋯ a 2 , n ⋮ ⋮ ⋱ ⋮ a n , 1 a n , 2 ⋯ a n , n ∣ = ∣ A ∣ det A= det \left( \begin{matrix} a_{1,1} & a_{1,2} & \cdots & a_{1,n}\\ a_{2,1} & a_{2,2} & \cdots & a_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ a_{n,1} & a_{n,2} & \cdots & a_{n,n} \end{matrix} \right)= \left| \begin{matrix} a_{1,1} & a_{1,2} & \cdots & a_{1,n}\\ a_{2,1} & a_{2,2} & \cdots & a_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ a_{n,1} & a_{n,2} & \cdots & a_{n,n} \end{matrix} \right|= |A| detA=det a1,1a2,1an,1a1,2a2,2an,2a1,na2,nan,n = a1,1a2,1an,1a1,2a2,2an,2a1,na2,nan,n =A

行列式的性质

性质1

A A A n n n阶矩阵,则 d e t A T = d e t A detA^T=detA detAT=detA

性质2

行列式任意两行(或两列)互换,行列式变号。

推论: 行列式某两行(或两列)相同时,行列式值为 0 0 0

性质3

将一行(或一列)的每个数乘实数 k k k,得到的行列式等于原来的行列式乘 k k k

推论: 行列式有两行(或两列)成比例,则行列式值为 0 0 0。特别地,当行列式有一行(或一列)全为 0 0 0时,行列式值为 0 0 0

性质4

∣ a 1 , 1 + b 1 , 1 a 1 , 2 ⋯ a 1 , n a 2 , 1 + b 2 , 1 a 2 , 2 ⋯ a 2 , n ⋮ ⋮ ⋱ ⋮ a n , 1 + b n , 1 a n , 2 ⋯ a n , n ∣ = ∣ a 1 , 1 a 1 , 2 ⋯ a 1 , n a 2 , 1 a 2 , 2 ⋯ a 2 , n ⋮ ⋮ ⋱ ⋮ a n , 1 a n , 2 ⋯ a n , n ∣ + ∣ b 1 , 1 a 1 , 2 ⋯ a 1 , n b 2 , 1 a 2 , 2 ⋯ a 2 , n ⋮ ⋮ ⋱ ⋮ b n , 1 a n , 2 ⋯ a n , n ∣ \left| \begin{matrix} a_{1,1}+b_{1,1} & a_{1,2} & \cdots & a_{1,n}\\ a_{2,1}+b_{2,1} & a_{2,2} & \cdots & a_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ a_{n,1}+b_{n,1} & a_{n,2} & \cdots & a_{n,n} \end{matrix} \right|= \left| \begin{matrix} a_{1,1}& a_{1,2} & \cdots & a_{1,n}\\ a_{2,1} & a_{2,2} & \cdots & a_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ a_{n,1} & a_{n,2} & \cdots & a_{n,n} \end{matrix} \right|+ \left| \begin{matrix} b_{1,1} & a_{1,2} & \cdots & a_{1,n}\\ b_{2,1} & a_{2,2} & \cdots & a_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ b_{n,1} & a_{n,2} & \cdots & a_{n,n} \end{matrix} \right| a1,1+b1,1a2,1+b2,1an,1+bn,1a1,2a2,2an,2a1,na2,nan,n = a1,1a2,1an,1a1,2a2,2an,2a1,na2,nan,n + b1,1b2,1bn,1a1,2a2,2an,2a1,na2,nan,n

对列也相同。

推论: 将行列式任意一行(或一列)乘一个实数 k k k再加到另一行(或另一列)上,行列式的值不变。

∣ a 1 , 1 a 1 , 2 ⋯ a 1 , n a 2 , 1 a 2 , 2 ⋯ a 2 , n ⋮ ⋮ ⋱ ⋮ a n , 1 a n , 2 ⋯ a n , n ∣ = ∣ a 1 , 1 + k ⋅ a j , 1 a 1 , 2 + k ⋅ a j , 2 ⋯ a 1 , n + k ⋅ a j , n a 2 , 1 a 2 , 2 ⋯ a 2 , n ⋮ ⋮ ⋱ ⋮ a n , 1 a n , 2 ⋯ a n , n ∣ \left| \begin{matrix} a_{1,1} & a_{1,2} & \cdots & a_{1,n}\\ a_{2,1} & a_{2,2} & \cdots & a_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ a_{n,1} & a_{n,2} & \cdots & a_{n,n} \end{matrix} \right|= \left| \begin{matrix} a_{1,1}+k\cdot a_{j,1} & a_{1,2}+k\cdot a_{j,2} & \cdots & a_{1,n}+k\cdot a_{j,n}\\ a_{2,1} & a_{2,2} & \cdots & a_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ a_{n,1} & a_{n,2} & \cdots & a_{n,n} \end{matrix} \right| a1,1a2,1an,1a1,2a2,2an,2a1,na2,nan,n = a1,1+kaj,1a2,1an,1a1,2+kaj,2a2,2an,2a1,n+kaj,na2,nan,n

行列式的计算方法

对于一个行列式
d e t A = ∣ a 1 , 1 a 1 , 2 ⋯ a 1 , n a 2 , 1 a 2 , 2 ⋯ a 2 , n ⋮ ⋮ ⋱ ⋮ a n , 1 a n , 2 ⋯ a n , n ∣ detA= \left| \begin{matrix} a_{1,1} & a_{1,2} & \cdots & a_{1,n}\\ a_{2,1} & a_{2,2} & \cdots & a_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ a_{n,1} & a_{n,2} & \cdots & a_{n,n} \end{matrix} \right| detA= a1,1a2,1an,1a1,2a2,2an,2a1,na2,nan,n
通过上述性质可将其变为上三角形式
d e t B = ∣ b 1 , 1 b 1 , 2 ⋯ b 1 , n 0 b 2 , 2 ⋯ b 2 , n ⋮ ⋮ ⋱ ⋮ 0 0 ⋯ b n , n ∣ detB= \left| \begin{matrix} b_{1,1} & b_{1,2} & \cdots & b_{1,n}\\ 0 & b_{2,2} & \cdots & b_{2,n}\\ \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & \cdots & b_{n,n} \end{matrix} \right| detB= b1,100b1,2b2,20b1,nb2,nbn,n

设变化过程中交换行(或列)的次数为 s s s,则 d e t A = d e t B = ( − 1 ) s ∏ i = 1 n b i , i detA=detB=(-1)^s\prod\limits_{i=1}^nb_{i,i} detA=detB=(1)si=1nbi,i

也就是说,我们可以通过类似高斯消元的方式,用 O ( n 3 ) O(n^3) O(n3)的时间复杂度来求一个 n n n阶行列式的值。


矩阵树定理

n ( 1 ≤ n ≤ 12 ) n(1\leq n\leq 12) n(1n12)个点,有一些点可以连边。求有多少种连边方案,可以使这 n n n个点形成一棵树。

矩阵树定理介绍

对于一个无向图 G G G,有以下几个概念:

  • G G G的度数矩阵 D [ G ] D[G] D[G]是一个 n ∗ n n*n nn的矩阵,且满足 d i , j = { 0 , i ≠ j 点 i 的度数 , i = j d_{i,j}= \begin{cases} 0,\qquad\qquad\quad i\neq j\\ 点i的度数,\quad i=j\quad \end{cases} di,j={0,i=ji的度数,i=j
  • G G G的邻接矩阵 A [ G ] A[G] A[G]也是一个 n ∗ n n*n nn的矩阵,且满足 a i , j = { 1 , 点 i 和点 j 之间有边相连 0 , 点 i 和点 j 之间没有边相连 a_{i,j}= \begin{cases} 1,&点i和点j之间有边相连\\ 0,&点i和点j之间没有边相连\quad \end{cases} ai,j={1,0,i和点j之间有边相连i和点j之间没有边相连

我们定义 G G G K i r c h h o f f Kirchhoff Kirchhoff矩阵 C [ G ] C[G] C[G] C [ G ] = D [ G ] − A [ G ] C[G]=D[G]-A[G] C[G]=D[G]A[G],则 G G G所有不同生成树的个数等于其 K i r c h h o f f Kirchhoff Kirchhoff矩阵 C [ G ] C[G] C[G]的任意一个 n − 1 n-1 n1阶主子式的行列式的绝对值。

n − 1 n-1 n1阶主子式: 对于 r ( 1 ≤ r ≤ n ) r(1\leq r\leq n) r(1rn),将 C [ G ] C[G] C[G]的第 r r r行和第 r r r列同时去掉后得到的新矩阵,表示为 C r [ G ] C_r[G] Cr[G]

那么对于上面这道题,我们只需要求出其 K i r c h h o f f Kirchhoff Kirchhoff矩阵 C [ G ] C[G] C[G],再求 d e t C [ G ] det C[G] detC[G]的任意一个 n − 1 n-1 n1阶主子式的行列式的绝对值即可。

举例

一下是一个 5 5 5个点, 6 6 6条边的无向图。

在这里插入图片描述

则其 K i r c h h o f f Kirchhoff Kirchhoff矩阵为
C [ G ] = ∣ 2 − 1 − 1 0 0 − 1 2 0 − 1 0 − 1 0 3 − 1 − 1 0 − 1 − 1 3 − 1 0 0 − 1 − 1 2 ∣ C[G]= \left| \begin{matrix} 2 & -1 & -1 & 0 & 0\\ -1 & 2 & 0 & -1 & 0\\ -1 & 0 & 3 & -1 & -1\\ 0 & -1 & -1 & 3 & -1\\ 0 & 0 & -1 & -1 & 2\\ \end{matrix} \right| C[G]= 2110012010103110113100112

r = 2 r=2 r=2
C 2 [ G ] = ∣ 2 − 1 0 0 − 1 3 − 1 − 1 0 − 1 3 − 1 0 − 1 − 1 2 ∣ = 2 ⋅ ∣ 3 − 1 − 1 − 1 3 − 1 − 1 − 1 2 ∣ − ( − 1 ) ⋅ ∣ − 1 0 0 − 1 3 − 1 − 1 − 1 2 ∣ = 2 × 8 + 1 × ( − 5 ) = 11 C_2[G]= \left| \begin{matrix} 2 & -1 & 0 & 0\\ -1 & 3 & -1 & -1\\ 0 & -1 & 3 & -1\\ 0 & -1 & -1 & 2\\ \end{matrix} \right| \\ \\ =2\cdot \left| \begin{matrix} 3 & -1 & -1\\ -1 & 3 & -1\\ -1 & -1 & 2\\ \end{matrix} \right|-(-1)\cdot \left| \begin{matrix} -1 & 0 & 0\\ -1 & 3 & -1\\ -1 & -1 & 2\\ \end{matrix} \right|= 2\times 8+1\times(-5)=11 C2[G]= 2100131101310112 =2 311131112 (1) 111031012 =2×8+1×(5)=11

上图生成树的个数就是 11 11 11个。

我们可以用类似高斯消元的方法来求行列式的值具体操作见下面例题的代码。其时间复杂度为 O ( n 3 ) O(n^3) O(n3)

证明过程比较繁琐,这里不做记录。并且在做题过程中也不需要证明,有了解,学会运用即可。


例题

SPOJ104 Highways

题目大意

给你一个有 n n n个点 m m m条边的无向图,求使每两个点间有且只有一条路线有多少方案(即求生成树的个数)。
1 ≤ n ≤ 12 1\leq n\leq 12 1n12,有多组数据。

题解

这就是一道矩阵树定理的板题。在代码中, g a u s s ( ) gauss() gauss()函数其实就是类似高斯消元的函数,利用辗转相除法,用 O ( n log ⁡ n ) O(n\log n) O(nlogn)的时间复杂度来使第 j j j行的第 i i i列的数变为 0 0 0。因为还要枚举当前行 i i i和需要修改的行 j j j,所以总时间复杂度为 O ( t ⋅ n 3 log ⁡ n ) O(t\cdot n^3\log n) O(tn3logn),对于这道题来说是可以过的。

code

#include<bits/stdc++.h>
using namespace std;
int t,n,m,x,y;
long long ans,a[105][105];
void gauss(){
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			while(a[j][i]){
				long long tp=a[i][i]/a[j][i];
				for(int v=i;v<=n;v++) a[i][v]-=a[j][v]*tp;
				for(int v=i;v<=n;v++) swap(a[i][v],a[j][v]);
			}
		}
	}
}
int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(int i=0;i<=100;i++){
			for(int j=0;j<=100;j++) a[i][j]=0;
		}
		for(int i=1;i<=m;i++){
			scanf("%d%d",&x,&y);
			--a[x][y];--a[y][x];
			++a[x][x];++a[y][y];
		}
		for(int i=1;i<=n;i++){
			a[i][n]=a[n][i]=0;
		}
		--n;
		gauss();
		ans=1;
		for(int i=1;i<=n;i++){
			ans=ans*a[i][i];
		}
		if(ans<0) ans=-ans;
		printf("%lld\n",ans);
	}
	return 0;
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值