[學習筆記]高斯消元、行列式、Matrix-Tree 矩陣樹定理

一、前置芝士:高斯消元

https://blog.csdn.net/xyz32768/article/details/78574746

二、行列式的定義

一個n方陣(行數和列數相等的矩陣) A 的行列式爲:

p1n(1)pi=1nA[i,pi]

記爲 det(A)|A|

三、行列式的性質

(1) |A|=|AT|
(2) |AB|=|A||B|
(3)矩陣的一行乘上 k 之後,行列式乘上 k
(4)如果矩陣的每一行內數的和都爲 0 ,每一列內數的和都爲 0 ,那麼行列式爲 0
(5)交換矩陣的兩行或兩列,行列式取反。
(6)矩陣的一行減去另一行的 k 倍,行列式不變。
性質(6)是求解行列式的關鍵。

四、求解行列式

暴力求解是 O(n2×n!) 的。
利用高斯消元求解行列式。
根據性質(6),我們可以 for i1n ,用第 i 行把所有滿足 j[i+1,n] 的位置 (j,i) 消成 0 ,也就是用第 i 行去消第 j 行。
最後原矩陣被消成一個上三角矩陣(對於每個 1in ,第 i 行前 i1 個元素全部爲 0 的矩陣)。
顯然這時候矩陣的行列式爲對角線上元素的乘積。
複雜度 O(n3)
代碼:

double det(int n) {
    int i, j, k;
    For (i, 1, n) {
        int p = i;
        For (j, i + 1, n)
            if (fabs(mat[j][i]) > fabs(mat[p][i])) p = j;
        if (p != i) For (j, i, n) swap(mat[i][j], mat[p][j]);
        For (j, i + 1, n) {
            double tmp = mat[j][i] / mat[i][i];
            For (k, i, n) mat[j][k] -= mat[i][k] * tmp;
        }
    }
    double ans = 1;
    For (i, 1, n) ans *= mat[i][i];
    return ans;
}

如果行列式特別大且題目要求取模,則可以利用逆元:

int det(int n) {
    int i, j, k, res = 1;
    For (i, 1, n) {
        int qaq = qpow(a[i][i], ZZQ - 2);
        For (j, i + 1, n) {
            int tmp = 1ll * a[j][i] * qaq % ZZQ;
            For (k, 1, n) a[j][k] = (a[j][k] - 1ll * a[i][k] *
                tmp % ZZQ + ZZQ) % ZZQ;
        }
    }
    For (i, 1, n) res = 1ll * res * a[i][i] % ZZQ;
    return res;
}

如果模數不是質數,可以利用輾轉相除的方法,複雜度多一個 log
具體地,如果當前要用第 i 行去消第 j 行,那麼:
(1)第 i 行減掉第 j 行的 A[i,i]A[j,i] 倍。這時候, A[i,i] 被消成 A[i,i]modA[j,i]
(2)交換第 i 行和第 j 行。注意,這個操作會導致行列式的取反,要用一個變量記錄當前行列式是否被取反。
(3)如果 A[j,i]=0 ,我們就成功地用第 i 行消去了第 j 行。否則繼續(1)(2)。
代碼:

int solve() {
    int i, j, k; bool tr = 0;
    For (i, 1, n) For (j, i + 1, n) {
        int a = mat[i][i], b = mat[j][i];
        while (b) {
            int tmp = a / b; a %= b; swap(a, b);
            For (k, i, n) mat[i][k] = (mat[i][k] - 1ll * tmp * mat[j][k]
                % ZZQ + ZZQ) % ZZQ;
            For (k, i, n) swap(mat[i][k], mat[j][k]); tr ^= 1;
        }
    }
    int ans = 1; For (i, 1, n) ans = 1ll * ans * mat[i][i] % ZZQ;
    return tr ? (ZZQ - ans) % ZZQ : ans;
}

五、應用:生成樹計數之矩陣-樹定理

n 階無向圖的一些定義:
鄰接矩陣 A :有邊 (i,j)A[i,j]=A[j,i]=1 ,否則爲 0 。特別地,如果圖有重邊,那麼 A[i,j]A[j,i] 等於邊 (i,j) 的條數。
度數矩陣 DD[i,i] 爲點 i 的度數,即由 i 發出的邊數。 D 其他位置的數爲 0
基爾霍夫矩陣: C=DA
基爾霍夫矩陣每行內數的和和每列內的和都爲 0 ,所以行列式爲 0
餘子式:一個矩陣 C 的餘子式 M[i,j] 表示 C 去掉第 i 行第 j 列後得到矩陣的行列式。
矩陣-樹定理,又稱基爾霍夫定理。先說結論:
無向圖的生成樹個數等於其基爾霍夫矩陣 C 的任意餘子式 M[i,i] (注意是 M[i,i] 不是 M[i,j] )的行列式。
如果圖不連通,那麼任意餘子式 M[i,i]0
證明:如果圖不連通,那麼每個連通塊內的點構成的矩陣仍然是基爾霍夫矩陣。
而連通塊不止一個,所以去掉第 i 行第 i 列之後,一定有一個連通塊仍然是基爾霍夫矩陣,也就是行列式爲 0

六、證明

首先證明:一棵樹,其基爾霍夫矩陣的任意餘子式 M[i,i] 等於 1
爲了方便討論,我們交換第 1 行和第 i 行,再交換第 1 列和第 i 列,我們要證明的只是 M[1,1]
1 爲根。
2n 的點重新排列,使同一個子樹內的點編號形成一個區間。
我們會發現,把第 1 行第 1 列去掉,就相當於分離了 1 的所有子樹。
我們可以把這個 n1 階方陣拆成 1 的度數個,每個小矩陣爲一個子樹的基爾霍夫矩陣,根爲 r 則矩陣第 r 行第 r 列加一。
易得 M[1,1] 爲這些小矩陣的行列式之積(因爲一個 ab 的排列和一個 b+1c 的排列合併起來,相當於對應 A 位置的乘積相乘,逆序對數相加)。
我們還要引入一個定理:
將基爾霍夫矩陣的第 1 行第 1 列憑空加上 1 之後,行列式等於 1
我們考慮用歸納法同時證明兩個結論。
考慮行列式的式子中,每個排列 p 對行列式的貢獻。
證明第二個結論:
先討論 p1=1 時,易得這對行列式的貢獻爲(1 的度數加 1 )再乘以所有子樹的(根所在主對角線位置加 1 後得到的行列式),也就是 1 的度數加 1
再考慮如果 p1=i ,那麼 i 一定是 1 的子節點。 i 的取法數爲 1 的度數。
分析一下可以得到,這時候 pi 必須爲 1 ,否則對行列式的貢獻爲 0
這樣看上去對行列式的貢獻爲 1 ,但是由於 p1=ipi=1 貢獻了一個逆序對,對行列式的貢獻爲 1
所以, p11 對行列式的貢獻爲 1 的度數)。
貢獻相加一下就證明了結論二。
於是結論一也得證。

一起來證明 Matrix-Tree 定理。
先構建一個輔助矩陣 B , 一個 m×n 的矩陣, m 爲邊數。
對於第 i 條邊 (u,v)B[i,u]=1,B[i,v]=1
易得 BTB=C
根據 Binet-Cauthy 定理:

|AB|=|S|=n|ASBS|

AS 表示 A 只保留向量集合 S 後得到的矩陣。
AS 表示 A 只保留向量集合 S 後得到的矩陣。
這個定理簡單地說,一個 n×m 的矩陣乘以一個 m×n 的矩陣後的行列式,等於枚舉一個大小爲 n 的集合 SS{1,2,...,m} ,求 AB 分別只保留 S 對應的列向量和行向量集合後的方陣乘積的行列式,並把所有 S 對應求出的行列式加起來。
所以:
Ai,j 表示 A 去掉第 i 行第 j 列後的子矩陣,
|Ci,i|=|S|=n1|BN/A,i,STBi,N/A,S|

=S=n1|Ci,i(S)|

C(S) 表示邊集 S 構成的基爾霍夫矩陣。
討論下這個式子。
相當於在 B 中選出 n1 條邊。
(1)選出的邊構成環或不連通。
實際上, n1 條邊連通 n 個點的形態只能是樹。
所以構成環和不連通其實是一樣的。
由之前證出的定理得到貢獻爲 0
(2)選出的邊構成樹。
根據基爾霍夫矩陣的性質,得到貢獻爲 1
於是得證!!!!!
實現時注意自環。

七、題目 & 推廣

[BZOJ4031][HEOI2015]小Z的房間:
https://www.lydsy.com/JudgeOnline/problem.php?id=4031
[BZOJ4596][Shoi2016]黑暗前的幻想鄉:
https://www.lydsy.com/JudgeOnline/problem.php?id=4596
Alice:爲什麼我們要證明矩陣-樹定理呢?
Bob:在應用中,矩陣-樹定理有一些拓展。
下面給出兩種常見拓展。
(1)有向圖生成樹計數。
①內向樹生成樹計數。
A 爲鄰接矩陣, D出度矩陣。
C=DA
root 爲根的內向生成樹個數就是 C 的餘子式 M[root,root] 的行列式。
②外向樹生成樹計數。
A 爲鄰接矩陣, D入度矩陣。
C=DA
root 爲根的外向生成樹個數就是 C 的餘子式 M[root,root] 的行列式。
[BZOJ5297][Cqoi2018]社交網絡:
https://www.lydsy.com/JudgeOnline/problem.php?id=5297
(2)邊帶權。
給定一個邊帶權的圖,求其所有生成樹的邊權積之和。
A 爲邊權矩陣, D 爲發出邊權和矩陣。
即對於一條邊 (u,v) ,邊權爲 wA[u,v]=A[v,u]=w
當然如果有重邊, A[u,v] 爲所有邊 (u,v) 的權值和。
D[u,u] 等於由 u 發出的所有邊的權值之和。
對於任意 uvD[u,v]=0
C=DA
所有生成樹的邊權積之和等於 C 的任意餘子式 M[i,i] 的行列式。
[BZOJ3534][Sdoi2014]重建:
https://www.lydsy.com/JudgeOnline/problem.php?id=3534

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章