• uva10766生成树计数


    此类题是给定一个无向图,求所有生成树的个数,生成树计数要用到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]表示。

    证明:http://blog.csdn.net/creationaugust/article/details/46389553

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

    #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
  • 相关阅读:
    Sky中国War3的旗帜
    2008流行趋势发布暨07届学生毕业秀(上海大学主办)
    随便写一下
    六一节——小朋友们快乐
    HEI
    Update my blog to improve my idea.
    由ipod引起的奇遇记
    加勒比海盗
    “老板娘”请客吃饭
    蚂蚁工坊
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/7146002.html
Copyright © 2020-2023  润新知