题目描述
题解
求一个n个点若干条边的图的生成树个数:
矩阵A
若
i≠j
,如果ij有边,那么A(i,j)=-1,否则A(i,j)=0
若
i=j
,那么A(i,j)为点i的度
将这个矩阵的前n-1行和前n-1列用高斯消元消成上三角
ans=abs(∏i=1n−1Ai,i)
这个做法是基于矩阵树定理
具体参考周冬2007集训队论文《生成树的计数及其应用》
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 105
const double eps=1e-9;
int T,n,m,x,y;
double du[N],a[N][N],ans;
void clear()
{
n=m=x=y=0;ans=0;
memset(du,0,sizeof(du));
memset(a,0,sizeof(a));
}
double gauss()
{
for (int i=1;i<n;++i)
{
int num=i;
for (int j=i+1;j<n;++j)
if (fabs(a[j][i])>fabs(a[num][i])) num=j;
if (num!=i)
for (int j=1;j<n;++j) swap(a[i][j],a[num][j]);
for (int j=i+1;j<n;++j)
if (fabs(a[j][i])>eps)
{
double t=a[j][i]/a[i][i];
for (int k=1;k<n;++k) a[j][k]-=a[i][k]*t;
}
}
double ans=1.0;
for (int i=1;i<n;++i) ans*=a[i][i];
return (ans>0)?ans:-ans;
}
int main()
{
scanf("%d",&T);
while (T--)
{
clear();
scanf("%d%d",&n,&m);
for (int i=1;i<=m;++i)
{
scanf("%d%d",&x,&y);
++du[x];++du[y];
if (x!=y) a[x][y]=a[y][x]=-1.0;
}
for (int i=1;i<=n;++i) a[i][i]=du[i]+0.0;
ans=gauss();
printf("%.0lf\n",ans+eps);
}
}