洛谷 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;
}
posted @ 2021-03-22 19:08  蓝田日暖玉生烟  阅读(47)  评论(0编辑  收藏  举报