洛谷 P6178 【模板】Matrix-Tree 定理 题解
一、题目:
二、思路:
简单说一下矩阵树定理。
设\(G(i,j)\)为点\(i\)和点\(j\)之间边权的总和,\(D(x,x)\)为\(\sum_{j=1}^n G(x,j)\)(可以理解为“度数”)。再设\(A=D-G\)。
如果是无向树,那么随便去掉\(A\)的某一行、某一列,求剩下矩阵的行列式。
如果是有向树,设根为\(x\),那么去掉\(A\)的第\(x\)行、第\(x\)列的行列式即可。
注意如果是外向树,\(D(x,x)=\sum_{i=1}^n G(i,x)\)。如果是内向树,\(D(x,x)=\sum_{j=1}^n G(x,j)\)。
三、代码:
#include <iostream>
#include <cstdio>
using namespace std;
inline long long read(void) {
long long x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return f * x;
}
const int maxn = 305;
const long long mod = 1e9 + 7;
int n, m, t;
long long a[maxn][maxn], b[maxn][maxn];
inline long long power(long long a, long long b) {
long long res = 1;
for (; b; b >>= 1) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
}
return res;
}
inline long long div(long long x) {
return power(x, mod - 2);
}
inline long long Gauss(void) {
long long res = 1;
for (int i = 1; i <= n; ++ i) {
int mx = i;
for (int j = i + 1; j <= n; ++ j) {
if (a[j][i] > a[mx][i]) mx = j;
}
if (a[mx][i] == 0) return 0;
if (mx != i) swap(a[i], a[mx]), res *= -1;
for (int j = i + 1; j <= n; ++ j) {
long long r = a[j][i] * div(a[i][i]) % mod;
for (int k = i; k <= n; ++ k) {
(a[j][k] -= r * a[i][k] % mod) %= mod;
if (a[j][k] < 0) a[j][k] += mod;
}
}
}
for (int i = 1; i <= n; ++ i) {
(res *= a[i][i]) %= mod;
}
if (res < 0) res += mod;
return res;
}
int main() {
n = read(); m = read(); t = read();
for (int i = 1; i <= m; ++ i) {
int x = read(), y = read(), w = read();
if (t == 0) {
(b[x][y] -= w) %= mod;
(b[y][x] -= w) %= mod;
(b[x][x] += w) %= mod;
(b[y][y] += w) %= mod;
} else {
(b[x][y] -= w) %= mod;
(b[y][y] += w) %= mod;
}
}
for (int i = 1; i < n; ++ i) {
for (int j = 1; j < n; ++ j) {
a[i][j] = b[i + 1][j + 1];
}
}
-- n;
printf("%lld\n", Gauss());
return 0;
}