此类题是给定一个无向图,求所有生成树的个数,生成树计数要用到Matrix-Tree定理(Kirchhoff矩阵-树定理)

G的度数矩阵D[G]是一个n*n的矩阵,并且满足:当i≠j时,dij=0;当i=j时,dij等于vi的度数

G的邻接矩阵A[G]也是一个n*n的矩阵, 并且满足:如果vi、vj之间有边直接相连,则aij=1,否则为0

我们定义G的Kirchhoff矩阵(也称为拉普拉斯算子)C[G]为C[G]=D[G]-A[G],则Matrix-Tree定理可以描述为:G的所有不同的生成树的个数等于其Kirchhoff矩阵C[G]任何一个n-1阶主子式的行列式的绝对值。所谓n-1阶主子式,就是对于r(1≤r≤n),将C[G]的第r行、第r列同时去掉后得到的新矩阵,用Cr[G]表示。

因为基尔霍夫矩阵i!=j处要么是0,要么是-1,这样处理起来就很方便

uva10766生成树计数_生成树uva10766生成树计数_ios_02
#include<map>
#include<set>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
#define ll long long
#define mod 1000000007
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define MIN(a,b) a<b ? a:b

using namespace std;

const double g=10.0,eps=1e-9;
const int N=50+10,maxn=500000+10,inf=0x3f3f3f3f;

ll D[N];
ll A[N][N];
ll solve(int n)
{
    ll ans=1;
    for(int i=1;i<n;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            while(A[j][i]){
                ll t=A[i][i]/A[j][i];
                for(int k=i;k<n;k++)
                    A[i][k]-=(A[j][k]*t);
                for(int k=i;k<n;k++)
                    swap(A[i][k],A[j][k]);
                ans=-ans;
            }
        }
        if(A[i][i]==0)return 0;
        ans*=A[i][i];
    }
    if(ans<0)ans=-ans;
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,k,m;
    while(cin>>n>>m>>k){
        for(int i=1;i<=n;i++)
        {
            D[i]=A[i][i]=0;
            for(int j=i+1;j<=n;j++)
                A[i][j]=A[j][i]=1;
        }
        while(m--){
            int a,b;
            cin>>a>>b;
            A[a][b]=A[b][a]=0;
        }
        for(int i=1;i<=n;i++)
            for(int j=1+i;j<=n;j++)
                if(A[i][j])
                   D[i]++,D[j]++;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i==j)A[i][j]=D[i];
                else A[i][j]=-A[i][j];
            }
        }
    /*    for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                cout<<A[i][j]<<" ";
            cout<<endl;
        }*/
        ll res=solve(n);
        cout<<res<<endl;
    }
    return 0;
}
View Code