重发下这篇原发于 2013-12-26 的网易博客
感觉这是我当年我写过的最有趣(?)的博客之一?但当时公式都是纯文本+等宽字体排版的,转到CSDN用latex重排一遍没那味儿了。。
然而这东西吧,如果你上了姚班,教计算机应用数学的姚先生或者教算法设计课的李老师会分分钟给你证了【手动捂脸】
但高中的时候我为了搞懂这个证明花了好久,搞懂之后当然也被自己感动了很久。。
愿诸位读者看完此文也能体会到搞懂一个大证明的快乐。。
另外欢迎大家报考姚班,讲课速度贼快,你值得拥有 【手动狗头】
英文叫Kirchhoff’s Matrix-Tree Theorem。
基尔霍夫的矩阵树定理……?
用[P]表示P为真时为1,假时为0。
用e.v,e.u表示边e的两端。
用 A ⊤ A^{\top} A⊤表示矩阵的转置。
首先我们考虑一棵n个结点的树,假设树上的边为{Ed[k]},那么我们构造一个矩阵:
T [ v , k ] = { 1 v = E d [ k ] . v − 1 v = E d [ k ] . u 0 otherwise ∀ 1 ≤ v ≤ n , 1 ≤ k ≤ n − 1 T[v,k] = \begin{cases} 1 & \quad v = \mathrm{Ed}[k].v \\ -1 & \quad v = \mathrm{Ed}[k].u \\ 0 & \quad \text{otherwise} \end{cases} \qquad\qquad \forall 1 \le v \le n, 1 \le k \le n - 1 T[v,k]=⎩⎪⎨⎪⎧1−10v=Ed[k].vv=Ed[k].uotherwise∀1≤v≤n,1≤k≤n−1
至于 E d [ k ] \mathrm{Ed}[k] Ed[k] 中谁当 v v v 谁当 u u u 其实无所谓……
共 n n n 个点 n − 1 n - 1 n−1 条边,所以这个矩阵是 n × ( n − 1 ) n \times (n - 1) n×(n−1) 的。
好……那么我们现在把它的第一行给删了。
于是变成方阵了233……我们还是称为矩阵 T T T。
举一个栗子:
相当于把1号点炸了,与之相连的边还剩个线头。
我们称之为被轰炸了的树。
现在我们来研究一下这个家伙的行列式。
考虑几个初等行列变换,由于每一列代表一条边,所以我们主要关注的焦点在列身上:
把第i列乘以 − 1 -1 −1:对其所对应的被轰炸了的树没有任何影响。反正 E [ k ] E[k] E[k] 中谁当 v v v 谁当 u u u 无所谓。
交换两列:行列式的值虽然取反了,但是对被轰炸了的树没有任何影响。反正边不分先后。
把第i列加到第j列上去:这个有点奇葩……但是我们可以考虑特殊情况,就是第i列中值为1的那一行在第j列恰好为-1,这样就成功消了个酱油。即 T [ u , i ] = 1 T[u, i] = 1 T[u,i]=1 而 T [ u , j ] = − 1 T[u, j] = -1 T[u,j]=−1,相加后 T [ u , j ] T[u, j] T[u,j] 消成0。然而第i列中值为-1的那一行(如果有的话),在第j列中一定为0,否则就有重边了。所以在第j列又会添上一个-1。对于被轰炸了的树来说,相当于这样:
第j条边从(v, u)变为了(v, w)。
而把第i列乘以-1加到第j列上去也是类似的。
这样一来,我们在被轰炸了的树上把边的一端改到别处去,就可以很开心地对应到行列式里的操作。而把第i列的值乘以k加到第j列上去行列式的值不变。
于是我们把刚才那棵被轰炸了的树玩一玩:
这样我们把所有的边的其中一端都炸飞了。
严格地说,我们可以这样玩:以已经被炸飞的1的灵魂为根,把每个结点连向父亲的那条边的父亲那一端炸飞。顺序从上到下,每次都通过自己已炸飞的父亲的边的线头让自己连向父亲的那一端变为线头。
这意味着什么?我们把行列式的列疯狂地交换一下,把某些列乘以-1,就得到了:
反正一开始的时候给定的边的顺序是任意的,也不好说det(T)到底是1还是-1吧……
我们索性写成 det ( T ) 2 = 1 \det(T)^2 = 1 det(T)2=1 好了。
这有什么用呢?其实我们得到了一个判断一个图是否是树的装置。
我们设一个
n
n
n 个点
m
m
m 条边的图
G
G
G 的边集是
{
E
d
[
k
]
}
\{\mathrm{Ed}[k]\}
{Ed[k]}。定义
G
G
G 的神奇关联矩阵E:
E
[
v
,
k
]
=
{
1
v
=
E
d
[
k
]
.
v
−
1
v
=
E
d
[
k
]
.
u
0
otherwise
∀
1
≤
v
≤
n
,
1
≤
k
≤
m
E[v,k] = \begin{cases} 1 & \quad v = \mathrm{Ed}[k].v \\ -1 & \quad v = \mathrm{Ed}[k].u \\ 0 & \quad \text{otherwise} \end{cases} \qquad\qquad \forall 1 \le v \le n, 1 \le k \le m
E[v,k]=⎩⎪⎨⎪⎧1−10v=Ed[k].vv=Ed[k].uotherwise∀1≤v≤n,1≤k≤m
当然了, m ≠ n − 1 m \ne n - 1 m=n−1 的话肯定不是树了……我们仅考虑 m = n − 1 m = n - 1 m=n−1 的情况。
把E的第一行给炸了。
这样我们得到E’
如前所述,如果G是一棵树,那么 det ( E ′ ) 2 = 1 \det(E')^2 = 1 det(E′)2=1。
要是不是树呢?
那么一定有环。好……如前所述,我们一定能把一个环上的边的端点乱改一通,从环上某一点v开始把环上的其它边的一段炸到v上去。
这样制造了一条重边!
在行列式里啥意思?随便乘以一下-1调整一下,就发现有两列相等!
于是根据行列式性质, det ( E ′ ) = 0 \det(E') = 0 det(E′)=0。
显然 det ( E ′ ) 2 = 0 \det(E')^2 = 0 det(E′)2=0 了。
1和0不是超开心?
1就是方案数++,0就是不管。
我们记一个图G的神奇关联矩阵为 E ( G ) E(G) E(G),炸了一行的神奇关联矩阵为 E ′ ( G ) E'(G) E′(G)。具体炸哪一行其实无所谓。
所以我们可以搞一个超大的式子算最后答案:
但是我们完全可以写得更开心一点:
注意我在某个神奇的地方加了个转置。为啥要这么干呢……
因为这个!
我们把几个矩阵神奇地拼成一个大矩阵。
其中I表示的是一个 m × m m \times m m×m 的单位矩阵。
举一个栗子:
然后就帅气了。
为了方便起见,我们令
A
=
E
′
(
G
)
A = E'(G)
A=E′(G),
B
=
E
′
(
G
)
⊤
B = E'(G)^\top
B=E′(G)⊤。令
n
′
=
n
−
1
n' = n - 1
n′=n−1
M
=
∣
A
0
−
I
B
∣
M = \begin{vmatrix} A & 0 \\ -I & B \end{vmatrix}
M=∣∣∣∣A−I0B∣∣∣∣
这究竟是是个啥?
根据行列式的那个啥定义,我们要选取所有排列 p p p,然后把 M [ i , p [ i ] ] M[i, p[i]] M[i,p[i]] 乘起来再乘以 ( − 1 ) p 中逆序对个数 (-1)^{p\text{ 中逆序对个数}} (−1)p 中逆序对个数 加起来。
形象地说就是在这个方阵中摆 m + n ′ m + n' m+n′ 个车,使之不能互相攻击。对于每个车来说,它要统计位于它右上方的车的数目,然后加起来就是逆序对。
我们把M的那四块用虚线分格的区域分别称作左上,右上,左下,右下。同时也称呼前 n ′ n' n′ 行、后 m m m 行,前 m m m 列、后 n ′ n' n′ 列表示横、竖虚线划分开的区域。
那么由 M M M 的样子知道……由于 M M M 的右上全是 0 0 0,所以前 n ′ n' n′ 行的车一定要放在左上才会对结果有贡献,也就是说在前 m m m 列中选 n ′ n' n′ 列出来。
那么现在到了后面的 m m m 行,列已经被瓜分了 n ′ n' n′ 列走了,前 m m m 列还剩 m − n ′ m - n' m−n′ 列,后半部分保存完好。
注意此时还是不能轻举妄动,因为车只要放在0上就sb了。
所以如果单位矩阵第i列未被取走,那么要有个车放在它的第 i i i 行第 i i i 列,也就是 M M M 的第 n ′ + i n' + i n′+i 行第 i i i 列。否则一定会导致有个倒霉车放在 0 0 0 上。
而剩下来的行,若编号为 n ′ + i n' + i n′+i,一定是第i列已在前 n ′ n' n′ 行放了车的。那么该行位于左下的唯一一个非0项已经不能放车了,于是它一定只能在后 n ′ n' n′ 列放车。
于是我们好像发现了什么?
假设我们已经选好了前 n ′ n' n′ 行要放车的 n ′ n' n′ 列,那么也就在后m行中删去了 m − n ′ m - n' m−n′ 行使得只剩下了 n ′ n' n′ 行,贡献了 m − n ′ m - n' m−n′ 个 − 1 -1 −1。于是剩下前面的那 n ′ n' n′ 行随意放车,后面删剩下的那 n ′ n' n′ 行随意放车。
相当于说,我选好了
n
′
n'
n′ 列后,把大家都删干净了,
A
A
A 变成一个
n
′
×
n
′
n' \times n'
n′×n′ 的
A
′
A'
A′ 了,
B
B
B 变成一个
n
′
×
n
′
n' \times n'
n′×n′ 的
B
′
B'
B′ 了,然后这部分对答案的贡献就变成了:
det
(
A
′
)
×
det
(
B
′
)
×
(
−
1
)
m
−
n
′
+
一些额外的逆序对数
\det(A') \times \det(B') \times (-1)^{m - n' + \text{一些额外的逆序对数}}
det(A′)×det(B′)×(−1)m−n′+一些额外的逆序对数
现在我们来考察“一些额外的逆序对”。假设我们将我们选取的那 n ′ n' n′ 列以及因此被选中的 n ′ n' n′ 行全染成黑色,其它为白色。那么我们得到了 n ′ n' n′ 个竖着的黑条条和 n ′ n' n′ 个横着的黑条条。
对于每个车来说,它要统计位于它右上方的车的数目,然后加起来就是逆序对。
在 det ( A ′ ) \det(A') det(A′) 中摆的车一定在 det ( B ′ ) \det(B') det(B′) 中摆的车的左上方,可以无视。
关键要关注的就是单位矩阵里所有主对角线上的白色格子。它们都是要放车的。考虑其中一个格子 v v v 的右上方。显然,如果右上方的车是 det ( A ′ ) \det(A') det(A′) 里的,那么它所在的竖着的黑条条一定在 v v v 的右边。如果右上方的车是 det ( B ′ ) \det(B') det(B′) 里的,那么它所在的横着的黑条条一定在 v v v 的上边。反着证回去就可以发现这是充要的。这样格子 v v v 对答案的贡献就是
右边的竖着的黑条条 + 上边横着的黑条条 \text{右边的竖着的黑条条} + \text{上边横着的黑条条} 右边的竖着的黑条条+上边横着的黑条条
也即 n ′ n' n′。
所以:
一些额外的逆序对数 = 单位矩阵里主对角线上的白色格子数 × n ′ = ( m − n ′ ) × n ′ \text{一些额外的逆序对数} = \text{单位矩阵里主对角线上的白色格子数} \times n' = (m - n') \times n' 一些额外的逆序对数=单位矩阵里主对角线上的白色格子数×n′=(m−n′)×n′
所以选好n’列后对答案的贡献是:
det ( A ′ ) × det ( B ′ ) × ( − 1 ) m − n ′ + ( m − n ′ ) × n ′ = det ( A ′ ) × det ( B ′ ) × ( − 1 ) m + m × n ′ − ( n ′ + 1 ) × n ′ = det ( A ′ ) × det ( B ′ ) × ( − 1 ) m + m × n ′ = det ( A ′ ) × det ( B ′ ) × ( − 1 ) m × ( n ′ + 1 ) \begin{aligned} &\det(A') \times \det(B') \times (-1)^{m - n' + (m - n') \times n'} \\ =&\det(A') \times \det(B') \times (-1)^{m + m \times n' - (n' + 1) \times n'} \\ =& \det(A') \times \det(B') \times (-1)^{m + m \times n'} \\ =& \det(A') \times \det(B') \times (-1)^{m \times (n' + 1)} \end{aligned} ===det(A′)×det(B′)×(−1)m−n′+(m−n′)×n′det(A′)×det(B′)×(−1)m+m×n′−(n′+1)×n′det(A′)×det(B′)×(−1)m+m×n′det(A′)×det(B′)×(−1)m×(n′+1)
事实上 n ′ n' n′ 列我是可以随意取的,取遍所有可能的 m m m 列中取 n ′ n' n′ 列的组合后,就是答案。
所以我们就推得了一个神奇的结论:
假设矩阵 A A A 是 n × m n \times m n×m,矩阵B是 m × n m \times n m×n,且 m > n m > n m>n
则:
其中:
A [ n ∗ S ] A[n*S] A[n∗S] 表示把 A A A 的 m m m 列删成只有编号属于 S S S 的列。
B [ S ∗ n ] B[S*n] B[S∗n] 表示把 A A A 的 m m m 行删成只有编号属于 S S S 的行。
M = ∣ A 0 − I B ∣ M = \begin{vmatrix} A & 0 \\ -I & B \end{vmatrix} M=∣∣∣∣A−I0B∣∣∣∣
还能更简洁么……
当然可以……
det
(
M
)
=
∣
A
0
−
I
B
∣
=
∣
0
A
B
−
I
B
∣
\begin{aligned} \det(M) &= \begin{vmatrix} A & 0 \\ -I & B \end{vmatrix} \\ &= \begin{vmatrix} 0 & AB \\ -I & B \end{vmatrix} \end{aligned}
det(M)=∣∣∣∣A−I0B∣∣∣∣=∣∣∣∣0−IABB∣∣∣∣
看起来是以矩阵为一个整体消元……其实是狂用“一行乘以k加到另一行上去,行列式的值不变”的性质。
然后我们给它们换一下位置:
∣
A
B
0
B
−
I
∣
\begin{vmatrix} AB & 0 \\ B & -I \end{vmatrix}
∣∣∣∣ABB0−I∣∣∣∣
这里是把n列提到前面去了。相当于每次提一个到前面去,重复n次,于是由于交换两列导致的正负号变化为:
( − 1 ) n × ( n + m − 1 ) = ( − 1 ) n × ( n − 1 ) + n × m = ( − 1 ) n × m (-1)^{n \times (n + m - 1)} = (-1)^{n \times (n - 1) + n \times m} = (-1)^{n \times m} (−1)n×(n+m−1)=(−1)n×(n−1)+n×m=(−1)n×m
那么我们现在得到的是个啥……
A B AB AB 是 n × n n \times n n×n 的, − I -I −I是 m × m m \times m m×m 的。
要想一个排列对行列式的值的贡献不为零,那么前 n n n 行不能取到右边的 0 0 0 那里去,所以只能在 A B AB AB 中玩。于是后 m m m 行也就只能在 − I -I −I 中玩了。
这样,实际上:
det
(
M
)
=
(
−
1
)
n
×
m
×
det
(
A
B
)
×
det
(
−
I
)
\det(M) = (-1)^{n \times m} \times \det(AB) \times \det(-I)
det(M)=(−1)n×m×det(AB)×det(−I)
而 det ( − I ) = ( − 1 ) m \det(-I) = (-1)^m det(−I)=(−1)m
所以 det ( M ) = ( − 1 ) m × ( n + 1 ) × det ( A B ) \det(M) = (-1)^{m \times (n + 1)} \times \det(AB) det(M)=(−1)m×(n+1)×det(AB)
(
−
1
)
m
×
(
n
+
1
)
(-1)^{m \times (n + 1)}
(−1)m×(n+1)之前见过吧……
于是我们就得到了柯西比内公式:
我废话那么多是干什么的?这样我们证明了:
于是我们只要求出
E
′
(
G
)
(
E
′
(
G
)
⊤
)
E'(G)(E'(G)^{\top})
E′(G)(E′(G)⊤) 这个矩阵,然后求出它的行列式就行了!
那么 E ′ ( G ) ( E ′ ( G ) ⊤ ) E'(G)(E'(G)^{\top}) E′(G)(E′(G)⊤) 到底是个*?以下把 E ( G ) E(G) E(G) 简写为 E E E
不妨来看 E E ⊤ EE^\top EE⊤,因为 E ′ E' E′ 比 E E E 少一行,所以最后乘积会少一行一列,所以先研究 E E ⊤ EE^\top EE⊤,然后删去第1行第1列就是。(当然根据前面的推导,你删第2行第2列其实也行……反正不会影响行列式的值)
再来回顾E是啥:
E
[
v
,
k
]
=
{
1
v
=
E
d
[
k
]
.
v
−
1
v
=
E
d
[
k
]
.
u
0
otherwise
∀
1
≤
v
≤
n
,
1
≤
k
≤
m
E[v,k] = \begin{cases} 1 & \quad v = \mathrm{Ed}[k].v \\ -1 & \quad v = \mathrm{Ed}[k].u \\ 0 & \quad \text{otherwise} \end{cases} \qquad\qquad \forall 1 \le v \le n, 1 \le k \le m
E[v,k]=⎩⎪⎨⎪⎧1−10v=Ed[k].vv=Ed[k].uotherwise∀1≤v≤n,1≤k≤m
设
L
=
E
E
⊤
L=EE^\top
L=EE⊤
则:
L
[
v
,
u
]
=
∑
k
=
1
m
E
[
v
,
k
]
E
[
u
,
k
]
L[v, u] = \sum_{k=1}^{m} E[v, k]E[u, k]
L[v,u]=k=1∑mE[v,k]E[u,k]
只要
E
[
v
,
k
]
E[v, k]
E[v,k] 和
E
[
u
,
k
]
E[u, k]
E[u,k] 中一个为0就对答案无贡献了。
所以我们貌似知道这到底是在干啥了……
- v = E d [ k ] . v , u = E d [ k ] . v v = \mathrm{Ed}[k].v, u = \mathrm{Ed}[k].v v=Ed[k].v,u=Ed[k].v 时, C [ v , v ] + + C[v, v]\mathtt{++} C[v,v]++
- v = E d [ k ] . v , u = E d [ k ] . u v = \mathrm{Ed}[k].v, u = \mathrm{Ed}[k].u v=Ed[k].v,u=Ed[k].u 时, C [ v , u ] − − C[v, u]\mathtt{--} C[v,u]−−
- v = E d [ k ] . u , u = E d [ k ] . v v = \mathrm{Ed}[k].u, u = \mathrm{Ed}[k].v v=Ed[k].u,u=Ed[k].v 时, C [ v , u ] − − C[v, u]\mathtt{--} C[v,u]−−
- v = E d [ k ] . u , u = E d [ k ] . u v = \mathrm{Ed}[k].u, u = \mathrm{Ed}[k].u v=Ed[k].u,u=Ed[k].u 时, C [ u , u ] + + C[u, u]\mathtt{++} C[u,u]++
所以其实L这个矩阵啊………设mat[v][u] = v与u间边的数量, deg[v] = v的度数。
他是这样的:
L
[
v
,
u
]
=
{
−
m
a
t
[
v
]
[
u
]
v
≠
u
d
e
g
[
v
]
v
=
u
L[v, u] = \begin{cases} -\mathrm{mat}[v][u] & \quad v \ne u \\ \mathrm{deg}[v] & \quad v = u \end{cases}
L[v,u]={−mat[v][u]deg[v]v=uv=u
即L = 度数矩阵 - 邻接矩阵
L我们称之为拉普拉斯矩阵。(怎么拉普拉斯的变换也神、算符也神、矩阵也神……)
所以我们花了一番周折,得到了基尔霍夫定理:
【基尔霍夫定理】一个无向图G的生成树个数为 det ( L ′ ) \det(L') det(L′)。其中 L ′ L' L′ 是 G G G 的拉普拉斯矩阵去掉第i行第i列的矩阵 ( 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n)。至于i具体是几其实无所谓。
呼啦啦……搞完了……