生成树的计数 Matrix-Tree定理
好像之前gerw学长讲过一遍毕姥爷讲过一遍,然而并不懂。本来不打算学的不巧两天内遇到了三道这样的题,十分难受。
定理如下。
1.G的度数矩阵D[G] 是一个n∗n的矩阵 当i≠j时,dij=0;当i=j时,dij等于i的度数;
2.G的邻接矩阵A[G];我们定义G的Kirchhoff矩阵(也称为拉普拉斯算子),C[G]=D[G]−A[G],则Matrix-Tree定理可以描述为:
G的所有不同的生成树的个数等于其Kirchhoff矩阵[G]任何一个n−1阶主子式的行列式的绝对值。
不会证。不想学。留个坑。可能也没有来填的机会了。
至少学会了怎么算行列式的值。。
认真地觉得我的代码写的十分优美。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<queue> #include<vector> typedef long long LL; const int maxn=100; using namespace std; double a[maxn][maxn]; int T,g[maxn][maxn],x,y,n,m; bool zero(double x) {return (x>0?x:-x)<1e-15;} double solve() { double res=1; for(int i=1;i<n;i++) { int now=i; for(int j=i+1;j<n;j++) if(a[j][i]>a[now][i]) now=j; if(now!=i) for(int j=i;j<n;j++) swap(a[i][j],a[now][j]); if(zero(a[i][i])) return 0; res*=a[i][i]; for(int j=i+1;j<n;j++) a[i][j]/=a[i][i]; a[i][i]=1; for(int j=i+1;j<n;j++) for(int k=i+1;k<n;k++) a[j][k]-=a[j][i]*a[i][k]; } if(res<0) res=-res; return res; } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=g[i][j]=0; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); g[x][y]=g[y][x]=1; a[x][x]++; a[y][y]++; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]-=g[i][j]; printf("%.0lf ",solve()); } return 0; }