https://vjudge.net/problem/SPOJ-HIGH
题意:
给n个点m条边,求生成树个数。
思路:
矩阵树裸题。
具体的话可以看一下周冬的论文《生成树的计数及其应用》。
简单说一下,$A[ ][ ]$为邻接矩阵,有边为1(其实也就是边的个数,有重边时要注意),无边为0。$D[ ][ ]$为度数矩阵,$i=j$时为1,否则为0。
$C[ ][ ]$为关联矩阵,$C[ ][ ]=D[ ][ ]-A[ ][ ]$。
最后解任意n-1阶的主子式即可。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,ll> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn=1000+5; 17 18 int n,m; 19 double C[maxn][maxn]; 20 int A[maxn][maxn],D[maxn][maxn]; 21 22 double Gauss() 23 { 24 for(int k=1; k<=n; k++) //k表示当前行数,因为行数与列数一样,所以这里k也代表了列数 25 { 26 int max_r=k; 27 for(int i=k+1;i<=n;i++) 28 if(fabs(C[i][k]>fabs(C[max_r][k]))) max_r=i; 29 if(C[max_r][k]==0) return 0; //有一列为0,行列式的值必为0 30 if(max_r!=k) 31 { 32 for(int j=k;j<=n;j++) 33 swap(C[k][j],C[max_r][j]); 34 } 35 for(int i=k+1;i<=n;i++) 36 { 37 double tmp=C[i][k]/C[k][k]; 38 for(int j=k;j<=n;j++) 39 C[i][j]-=tmp*C[k][j]; 40 } 41 } 42 double ans=1; 43 for(int i=1;i<=n;i++) ans*=C[i][i]; //化为三角阵后计算主对角线元素乘积 44 ans=fabs(ans); 45 return ans; 46 } 47 48 int main() 49 { 50 //freopen("in.txt","r",stdin); 51 int T; 52 scanf("%d",&T); 53 while(T--) 54 { 55 memset(A,0,sizeof(A)); 56 memset(D,0,sizeof(D)); 57 scanf("%d%d",&n,&m); 58 for(int i=0;i<m;i++) 59 { 60 int u,v; 61 scanf("%d%d",&u,&v); 62 D[u][u]++; D[v][v]++; 63 A[u][v]++; A[v][u]++; 64 } 65 n--; 66 for(int i=1;i<=n;i++) 67 for(int j=1;j<=n;j++) 68 C[i][j]=D[i][j]-A[i][j]; 69 printf("%.0lf\n",Gauss()); 70 } 71 return 0; 72 }
时间: 2024-10-29 03:37:58