[模板]矩阵树定理
用途
求生成树个数
做法
定义度数矩阵A,A[i][i]为i号点的度数;邻接矩阵B,B[i][j]为点i到j的边数
对于无向图,用A-B,然后随意选一个i,去掉第i行和第i列,它的行列式就是生成树个数
对于有向图,外向树的个数就是把度数矩阵换成入度矩阵;内向树的个数就是换成出度矩阵;删掉的行列一定要是根
行列式求法
首先有三条内容:
1.交换矩阵的两行,行列式取反
2.用矩阵一行加减一行的倍数,行列式不变
3.上三角矩阵的行列式为主对角线元素的积
于是可以高斯消元成上三角矩阵
例题
bzoj4894 天赋(有向图外向树个数)
1 #include<bits/stdc++.h> 2 #include<tr1/unordered_map> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 #define MP make_pair 5 using namespace std; 6 typedef long long ll; 7 typedef unsigned long long ull; 8 typedef pair<int,int> pa; 9 const int maxn=305,P=1e9+7; 10 11 inline ll rd(){ 12 ll x=0;char c=getchar();int neg=1; 13 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 14 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 15 return x*neg; 16 } 17 18 int N,a[maxn][maxn]; 19 char s[maxn]; 20 21 inline int fpow(int x,int y){ 22 int re=1; 23 while(y){ 24 if(y&1) re=1ll*x*re%P; 25 x=1ll*x*x%P,y>>=1; 26 }return re; 27 } 28 29 int main(){ 30 //freopen("","r",stdin); 31 N=rd(); 32 for(int i=1;i<=N;i++){ 33 scanf("%s",s+1); 34 for(int j=2;j<=N;j++){ 35 if(s[j]=='1'){ 36 a[j-1][j-1]++; 37 if(i!=1) a[i-1][j-1]--; 38 } 39 } 40 }N--; 41 int ans=1; 42 for(int i=1;i<=N;i++){ 43 int mi=i; 44 for(int j=i+1;j<=N;j++){ 45 if(a[j][i]) mi=j; 46 } 47 if(mi!=i) ans*=-1,swap(a[mi],a[i]); 48 for(int j=i+1;j<=N;j++){ 49 int r=1ll*a[j][i]*fpow(a[i][i],P-2)%P; 50 for(int k=i;k<=N;k++){ 51 a[j][k]=(a[j][k]-1ll*a[i][k]*r)%P; 52 } 53 } 54 } 55 for(int i=1;i<=N;i++) ans=1ll*ans*a[i][i]%P; 56 printf("%d\n",(ans+P)%P); 57 return 0; 58 }