生成树计数,matrix-tree定理的应用。
Matrix-tree定理:
D为无向图G的度数矩阵(D[i][i]是i的度数,其他的为0),A为G的邻接矩阵(若u,v之间存在边,A[u][v]=A[v][u]=1),C=D-A。
对于一个无向图G,它的生成树个数等于其Kirchhoff矩阵任何一个n-1阶主子式的行列式的绝对值。 所谓n-1阶主子式,就是对于任意一个r,将C的第r行和第r列同表示时删去后的新矩阵,表示为Cr。
求行列式的值:
把矩阵用高斯消元消成上三角矩阵,对角线的积就是行列式的值。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 7 using namespace std; 8 9 const double eps = 1e-15; 10 11 double c[20][20]; 12 int T,n,m; 13 14 double Gauss() { 15 for (int k=1; k<=n; ++k) { 16 int r = k; 17 for (int i=k+1; i<=n; ++i) 18 if (fabs(c[i][k]) > fabs(c[r][k])) r = i; 19 if (r!=k) for (int j=1; j<=n; ++j) swap(c[k][j],c[r][j]); 20 for (int i=k+1; i<=n; ++i) 21 if (fabs(c[i][k]) > eps) { 22 double t = c[i][k] / c[k][k]; 23 for (int j=k; j<=n; ++j) c[i][j] -= t*c[k][j]; 24 } 25 } 26 double ans = 1.0; 27 for (int i=1; i<=n; ++i) ans = ans*c[i][i]; //矩阵的对角线乘积 28 return (ans > 0) ? ans : -ans;//取绝对值 29 } 30 31 int main() { 32 scanf("%d",&T); 33 while (T--) { 34 memset(c,0,sizeof(c)); 35 scanf("%d%d",&n,&m); 36 for (int u,v,i=1; i<=m; ++i) { 37 scanf("%d%d",&u,&v); 38 c[u][v] = c[v][u] = -1;//边 39 c[u][u] ++;c[v][v] ++;//度数 40 } 41 n--; // 去掉最后一行最后一列 42 double ans = Gauss(); //高斯消元 43 printf("%.0lf\n",ans+eps); 44 } 45 return 0; 46 }