矩阵树定理

简述

Kirchhoff 矩阵树定理(简称矩阵树定理)解决了一张图的生成树个数计数问题。

主要步骤

无向图

假设现在给定一个无向图\(G\)
定义度数矩阵\(D\):若存在边\((u,v,w)\),则\(D[u][u]+=w,D[v][v]+=z\)
定义邻接矩阵\(C\):若存在边\((u,v,w)\),则\(C[u][v]+=w,C[v][u]+=w\)
图G的基尔霍夫矩阵\(A=D-C\)
删去任意一行和任意一列,求剩下的矩阵行列式,即为所有生成树的边权积的和
当所有边边权为1时就是生成树的个数

有向图

假设现在给定一个有向图\(G\)
定义度数矩阵\(D\):若存在边\((u,v,w)\),则外向树中\(D[v][v]+=z\),内向树中\(D[u][u]+=w\)
定义邻接矩阵\(C\):若存在边\((u,v,w)\),则内向树和外向树中均\(C[u][v]+=w\)
图G的基尔霍夫矩阵\(A=D-C\)
删去任意一行和任意一列,求剩下的矩阵行列式,即为所有生成树的边权积的和
当所有边边权为1时就是生成树的个数

code

给定一张 \(n\) 个结点 \(m\) 条边的带权图(可能为无向图,可能为有向图)。
定义其一个生成树 \(T\) 的权值为 \(T\) 中所有边权的乘积。
求其所有不同生成树的权值之和,对 \(10^9\) 取模。

点击查看代码
#include<bits/stdc++.h>
#define il inline
#define cs const
#define ri register
#define int long long//
using namespace std;
namespace Q{
    il int rd(){
        ri int x=0;bool f=0;ri char c=getchar();
        while(!isdigit(c)) f|=(c=='-'),c=getchar();
        while(isdigit(c)) x=x*10+(c^48),c=getchar();
        return f?-x:x;
    }
    il void wt(int x){
        if(x<0) x=-x,putchar('-');
        if(x>=10) wt(x/10);
        return putchar(x%10+48),void();
    }
    il int qpow(int a,int b,int p=1e9+7){
        ri int as=1;
        while(b>0){
            if(b&1) as=as*a%p;
            a=a*a%p,b>>=1;
        }
        return as;
    }
    il int inv(int a,int p=1e9+7){
        return qpow(a,p-2,p);
    }
} using namespace Q;
cs int N=305,mod=1e9+7;
int n,m,t;
struct matrix{
    int o[N][N];
    il int getdet(int p=1e9+7){
        ri int as=1,iv,l;
        for(ri int i=2;i<=n;++i){
            if(!o[i][i]){
                for(ri int j=i+1;j<=n;++j){
                    as*=-1,swap(o[i],o[j]);
                }
            }
            iv=inv(o[i][i]);
            for(ri int j=i+1;j<=n;++j){
                l=o[j][i]*iv%p;
                for(ri int k=i;k<=n;++k){
                    o[j][k]=(o[j][k]-o[i][k]*l%p+p)%p;
                }
            }
            as=as*o[i][i]%p;
            if(!as) return 0;
        }
        return as;
    }
}a;
signed main(){
    n=rd(),m=rd(),t=rd();
    for(ri int i=1,u,v,w;i<=m;++i){
        u=rd(),v=rd(),w=rd()%mod;
        a.o[v][v]=(a.o[v][v]+w)%mod,a.o[u][v]=(a.o[u][v]-w+mod)%mod;
        if(!t) a.o[u][u]=(a.o[u][u]+w)%mod,a.o[v][u]=(a.o[v][u]-w+mod)%mod;
    }
    wt(a.getdet());
    return 0;
}

edit

posted @ 2023-01-28 20:11  雨夜风月  阅读(124)  评论(0编辑  收藏  举报