筆記-矩陣樹定理
阿新 • • 發佈:2022-06-05
無向圖生成樹計數
考慮構建拉普拉斯矩陣:
\[L(i,j)=\left\{ \begin{aligned} -m(i,j)(i\ne j) \\ deg(i,j)(i=j) \\ \end{aligned} \right. \]在去某一行和列後 \(det(L)\) 即為答案。
證明略(後面有時間會補)。
模板:P4111
行列式即為變換為上三角矩陣後對角線上的乘積,所以高斯消元即可。
但是這道垃圾題模數不是質數,我們通過輾轉相除即可。
複雜度 \(\tilde{O}((nm)^3)\)。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 1e9; int n, m, num, id[11][11]; char s[11]; ll L[101][101]; int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0}; ll Gauss() { ll ret = 1; int N = num - 1; for (int i = 1; i <= N; i++) { for (int j = i + 1; j <= N; j++) {//消第 j 行 while (L[j][i]) { ll rate = L[i][i] / L[j][i]; for (int k = i; k <= N; k++) { L[i][k] = (L[i][k] - L[j][k] * rate % mod + mod) % mod; } swap(L[i], L[j]); ret = -ret; } } ret = ret * L[i][i] % mod; ret = (ret + mod) % mod; } return ret; } int main() { cin >> n >> m; for (int i = 1; i <= n; i++) { scanf("%s", s + 1); for (int j = 1; j <= m; j++) { if (s[j] == '.') id[i][j] = ++num; } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (!id[i][j]) continue; for (int k = 0; k < 4; k++) { if (!id[i + dx[k]][j + dy[k]]) continue; L[id[i][j]][id[i][j]]++; L[id[i][j]][id[i + dx[k]][j + dy[k]]]--; } } } cout << Gauss() << "\n"; return 0; }
有向圖有根外向樹計數
重新定義拉普拉斯矩陣:
\[L(i,j)=\left\{ \begin{aligned} -m(i,j)(i\ne j) \\ out(i)(i=j) \\ \end{aligned} \right. \]有向圖有根外向樹計數
重新定義拉普拉斯矩陣:
\[L(i,j)=\left\{ \begin{aligned} -m(i,j)(i\ne j) \\ in(i)(i=j) \\ \end{aligned} \right. \]注意有向圖定根必須去掉根的那行和那列。