矩阵树定理与BEST定理

行列式#

定义:det(A),又记作 |A|,等于 p(1)τ(p)i=1nAi,pi,其中 p1n 的排列,τ(p) 表示排列 p 的逆序对数。

1. 对于一个上三角矩阵,他的行列式等于主对角线所有值的乘积。

要使 An,pn0pn 只能取 n;要使 An1,pn10pn1{n1,n},但是 n 已经被用过了,pn1=n1

以此类推,使 Ai,pi 非零的只有唯一一个排列 pi=i,此时 τ(p)=0

2. 单位矩阵的行列式为 1,即 |I|=1

根据 Ii,j=[i=j] 以及 定理1 易证。

3. 交换矩阵两行,行列式变号。

交换 ij 等价于交换每个排列的 pi,pj,这会使所有 τ(p) 奇偶性改变,相当于整体乘了个 1

4. 将矩阵某行乘上一个常数,行列式乘上相同常数。

不妨将第 r 行所有元素乘 ki=1nAi,pi 恰好包含一个第 r 行元素,把 k 提出来。

5. 若矩阵有相同的两行,则行列式为 0

交换两行会使行列式变号,但是矩阵没变,即 |A|=|A||A|=0

6. 若矩阵有两行存在倍数关系,则行列式为 0

k|A|=k|A||A|=0

7. 若两个矩阵至多有一行不等,将这不等的一行相加得到的新矩阵的行列式等于原行列式之和。

设不等的行编号为 c,新矩阵 S 满足 Si=Ai=Bi, Sc=Ac+Bc(ic)

i=1nSi,pi=(Ac,pc+Bc,pc)i=1n[ic]Ai,pi=i=1nAi,pi+i=1nBi,pi

8. 将矩阵的某行加上另一行的倍数,行列式不变。

设把 ck 倍加到 d 上,设新矩阵为 C

Bi=Ai,Bd=kAc(ic),根据定理 7可得 |A|+|B|=|C|,根据定理6可得 |B|=0

高斯消元#

步骤略。

P4783 【模板】矩阵求逆

题意:求一个 n×n 的矩阵 A 在模 109+7 意义下的逆矩阵。

A 进行线性变换相当于左乘一个矩阵,也就是说把 A 变换(消元)到单位矩阵 I,相当于左乘 A1

有恒等式 A1×A=I,那么在 A 变换到 I 的同时 I 也做同样的变换,最后得到 A1×I=A1

矩阵可逆当且仅当 |A|0,即满秩。submission

P7112 【模板】行列式求值

题意:给定一个 n 阶行列式,求 |A|。结果对 p 取模,不保证 p 是素数。

A 消成上三角矩阵,最后答案就是主对角线之积。

加上某一行的倍数不改变答案,而交换两行会使符号改变,因此记录交换了多少次。

没有必要对一行乘某个常数的操作,否则还有额外记录乘了多少东西。

p 没有特殊性质,不能求逆元,因此采用类似「辗转相除法」对两行消元,时间复杂度 O(n3logp)

#include<bits/stdc++.h>
#define eb emplace_back
#define ep emplace
using namespace std;

using ll = long long;

int n, p, sgn; ll a[605][605];

int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin >> n >> p;
	for(int i = 1; i <= n; ++ i) {
		for(int j = 1; j <= n; ++ j) {
			cin >> a[i][j];
			a[i][j] %= p;
		}
	}
	for(int k = 1; k <= n; ++ k) {
		for(int i = k; i <= n; ++ i) {
			if(a[i][k]) {
				if(i != k) {
					swap(a[i], a[k]), sgn ^= 1;
				}
				break;
			}
		}
		if(!a[k][k]) return cout << 0, 0;
		for(int i = k + 1; i <= n; ++ i) {
			while(a[i][k]) {
				if(a[i][k] < a[k][k]) {
					swap(a[i], a[k]), sgn ^= 1;
				} 
				ll q = a[i][k] / a[k][k];
				for(int j = k; j <= n; ++ j) {
					a[i][j] = (a[i][j] + p - q * a[k][j] % p) % p;
				}
			}
		}
	}
	ll tmp = 1;
	for(int i = 1; i <= n; ++ i) tmp = tmp * a[i][i] % p;
	cout << (sgn ? (p - tmp) % p : tmp);
	return 0;
}

矩阵树定理#

无向图生成树个数

G 是一个有 n 个点的无向图,定义度数矩阵 D 为:

Dii=deg(i), Dij=0, ij

e(i,j) 表示点 i 与点 j 相连的边数,并定义邻接矩阵 A 为:

Aij=Aji=e(i,j), ij

定义拉普拉斯矩阵:

L=DA

记图 G 的所有生成树个数为 t

t(G)=detL(1,2,,i1,i+1,,n1,2,,i1,i+1,,n)

其中记号 L(G)(1,2,,i1,i+1,,n1,2,,i1,i+1,,n) 表示矩阵 L 的第 [1,i)(i,n] 行与 [1,i)(i,n] 列构成的子矩阵。

无向图拉普拉斯矩阵所有 n1 阶主子式都相等。

有向图生成树个数

定义出度矩阵 Dout(i,i)=degout(i),Dout(i,ji)=0

e(i,j) 表示 i 指向 j 的有向边数,定义邻接矩阵 A

Aij=e(i,j), ji

定义出度拉普拉斯矩阵 Lout

Lout=DoutA

同理定义入度矩阵 Din,Lin

记以 r 为根的所有内向生成树个数为 troot(r),内向表示所有边全部指向父亲。

记以 r 为根的所有外向生成树个数为 tleaf(r),外向表示所有边全部指向儿子。

troot(r)=detLout(1,2,,k1,k+1,,n1,2,,k1,k+1,,n)tleaf(r)=detLin(1,2,,k1,k+1,,n1,2,,k1,k+1,,n)

边权积的和

对于一条 (u,v,w) 会对该方案贡献 w 的系数,这等价于拆成 w(u,v),方案数乘 w

BEST定理#

G 是有向欧拉图,那么 G 的不同欧拉回路总数:

ec(G)=troot(k)vV(degout(v)1)!

欧拉图任意节点为根的外向树数量相等,且所有节点出度和入度相等(这也说明 troot(k)=tleaf(k))。

注意:BEST定理只能在欧拉图上使用。

P5807 【模板】BEST 定理 | Which Dreamed It

题意:求从 1 开始的欧拉回路数量。

对于一条欧拉回路,保留除 1 外所有点路径中的最后一条出边,1 的出边全部删掉。

此时图中一定无环。

这样除了 1 每个点会被保留恰好一条出边,且整张图连通,形成一颗以 1 为根的内向树。

我们钦定一棵内向树,然后对于其他边任意定顺序,一定唯一对应一个欧拉回路。

充分性有了,考虑必要性,显然每一个欧拉回路都唯一对应一颗内向树和其中遍历出边的顺序。

因此总方案就是

troot(1)×d1!×i1(di1)!

由此可以引出BEST定理,统计整张图本质相同的欧拉回路个数(循环同构)。

1 会在一个欧拉回路会出现 d1 次,每种方案都能旋转生成 d1 中以 1 为起点的方案,因此每种方案被重复计算 d1 次:

troot(1)(di1)!

submission

posted @   Lu_xZ  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示