矩阵树定理

今天学习了矩阵树定理,就是求解无向图最小生成树个数的一个东西
首先需要构造无向图的基尔霍夫矩阵,我们记为矩阵K。矩阵K满足,

K = D − A K = D - A K=DA

其中D是这个无向图的度数矩阵,在对角线上值是每个点的度数,其他位置的值都是0,A是这个无向图的出入度矩阵,第 i i i j j j 列元素表示点 i i i 到点 j j j 之间的边数

这个矩阵 K K K,随意选择下标相同的一行一列挖去,那么剩下的行列式的值就是这个无向图的最小生成树个数。

行列式具有以下性质(针对行,列同理)

  1. 交换任意两行,行列式的值乘-1
  2. 如果任意两行相同,行列式的值为0
  3. 行列式中某一行的系数可以提取到行列式外
  4. 行列式中,某一行可以表示成两个数相加的形式,那么可以从这一行拆开,行列式的值就是拆分后两个行列式的和
  5. 行列式对应矩阵做第三类初等变换,某一行乘k加到另一行,行列式的值不变

通过这些性质,我们知道了行列式的值可以使用高斯消元来求解

P4111 [HEOI2015]小 Z 的房间

这是一个矩阵树的模板题,按上述的方式建图,并且最后注意高斯消元求解行列式的时候,我们需要取mod,因此我们要使用辗转相除的方法来完成一次消元,因此整体的时间复杂度 O ( n m 2 l o g ( n ) ) O(nm^2log(n)) O(nm2log(n))

#include 
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int Gcd(int a,int b){if (b == 0) return a; return Gcd(b , a%b);}
int Lcm(int a, int b){ return a/Gcd(a,b)*b;}
inline long long read(){
   long long f = 1, x = 0;char ch = getchar();
    while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
    while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
const int maxn = 1e3 + 10;
const LL mod = 1e9;
char s[maxn][maxn];
int id[maxn][maxn];
LL a[maxn][maxn];
int n,m,tot;
void add(int u,int v){
    a[u][v]--;
    a[v][u]--;
    a[u][u]++;
    a[v][v]++;
}
LL gauss(int n){
    LL ans = 1;
    for(int i=1; i<=n; i++){
        for(int k=i+1; k<=n; k++){
            while(a[k][i]){
                LL d = a[i][i] / a[k][i];
                for(int j=i; j<=n; j++){
                    a[i][j] = (a[i][j] - 1ll * d * a[k][j] % mod + mod) % mod;
                }
                swap(a[i],a[k]);
                ans = -ans;
            }
        }
        ans = 1ll * ans * a[i][i] % mod;
        ans = (ans + mod) % mod;
    }
    return ans;
}
int main(){
    n = read(),m = read(),tot = 0;   
    for(int i=1; i<=n; i++){
        scanf("%s",s[i] + 1);
        for(int j=1; j<=m; j++){
            if (s[i][j] == '.'){
                id[i][j] = ++tot;
            }
        }
    }
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++){
            if (s[i][j] == '.'){
                if (id[i-1][j]){
                    add(id[i-1][j],id[i][j]);
                }
                if (id[i][j-1]){
                    add(id[i][j-1],id[i][j]);
                }
            }
        }
    }   
    cout << (gauss(tot - 1) % mod + mod) % mod << endl;
    return 0;
}```

你可能感兴趣的:(矩阵树)