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;
}

时间: 2024-07-31 08:31:59

uva10766生成树计数的相关文章

bzoj1002 生成树计数 找规律

这道题第一眼是生成树计数,n是100,是可以用O(n^3)的求基尔霍夫矩阵的n-1阶的子矩阵的行列式求解的,但是题目中并没有说取模之类的话,就不好办了. 用高精度?有分数出现. 用辗转相除的思想,让它不出现分数.但过程中会出现负数,高精度处理负数太麻烦. 用Python打表?好吧,Python还不熟,写不出来..... 所以,如果这道题我考场上遇到,最多用double骗到n<=20的情况的部分分. 最终只能求助于题解了... 好像是通过观察行列式的特点,推导出关于答案f(n)的递推式(f(n)=

生成树计数

生成树计数就是统计一张图中一共有多少种构造生成树的方案. 大概要用到组合数学等等的数学知识. 以下内容均来自NOI2007国家集训队论文 周冬 <生成树的计数及其应用>: ------------------------- Matrix-Tree定理(Kirchhoff矩阵-树定理).Matrix-Tree定理是解决生成树计数问题最有力的武器之一.它首先于1847年被Kirchhoff证明.在介绍定理之前,我们首先明确几个概念: 1.G的度数矩阵D[G]是一个n*n的矩阵,并且满足:当i≠j时

kuangbin带你飞 生成树专题 : 次小生成树; 最小树形图;生成树计数

第一个部分 前4题 次小生成树 算法:首先如果生成了最小生成树,那么这些树上的所有的边都进行标记.标记为树边. 接下来进行枚举,枚举任意一条不在MST上的边,如果加入这条边,那么肯定会在这棵树上形成一个环,如果还要维护处树的特点 那么就要在这个环上删去一条边,这样他还是树,删掉的边显然是这条链上权值最大边更可能形成次小生成树.那么就有2中方法可以做. 第一种PRIM在prim时候直接可以做出这个从I到J的链上权值最大的值MAX[i][j]; 同时可以用kruskal同样方式标记树边,然后DFS跑

Uva 10766 Organising the Organisation (Matrix_tree 生成树计数)

题目描述: 一个由n个部门组成的公司现在需要分层,但是由于员工间的一些小小矛盾,使得他们并不愿意做上下级,问在满足他们要求以后有多少种分层的方案数? 解题思路: 生成树计数模板题,建立Kirchhoff矩阵,利用Matrix_tree定理求解. Kirchhoff矩阵:假设G为n*n矩阵,C为G的入度矩阵(i==j时,C[i][j]等于i的入度;i!=j时,C[i][j]等于零),A为G的邻接矩阵,那么就有Kirchhoff矩阵等于C-A. Matrix_tree定理:G的不同生成树的个数等于其

SPOJ104 Highways,生成树计数

高速公路(SPOJ104 Highways) 一个有n座城市的组成国家,城市1至n编号,其中一些城市之间可以修建高速公路.现在,需要有选择的修建一些高速公路,从而组成一个交通网络.你的任务是计算有多少种方案,使得任意两座城市之间恰好只有一条路径? 数据规模:1≤n≤12. 生成树计数 算法步骤: 1. 构建拉普拉斯矩阵 Matrix[i][j] = degree(i) , i==j -1,i-j有边 0,其他情况 2. 去掉第r行,第r列(r任意) 3. 计算矩阵的行列式 #include <m

bzoj 1005: [HNOI2008]明明的烦恼 prufer编号&amp;&amp;生成树计数

1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2248  Solved: 898[Submit][Status] Description 自从明明学了树的结构,就对奇怪的树产生了兴趣...... 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度

生成树计数模板

#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=55; typedef long long LL; int D[N][N]; LL C[N][N];//Kirchhoff矩阵 LL Det(LL a[][N],int n)//生成树计数:Matrix-

【生成树计数】专题总结

在CTSC和APIO上好像经常听到生成树计数这东西 于是就去看了下论文 蒟蒻表示看不懂证n明orz 反正懂用就行了.. 生成树计数 生成树计数就是给出一种n个点的无向图G 求这n个点的生成树个数 G的度数矩阵d[i][j] 当i≠j时d[i][j]=0 否则等于i点的度数 G的邻接矩阵a[i][j] a[i][j]=i.j间的边的个数(能有重边) Kirchhoff矩阵 c[i][j]=d[i][j]-a[i][j] Kirchhoff矩阵的n-1阶主子式的行列式的值的绝对值即为生成树的个数 n

HDU4305:Lightning(生成树计数+判断点是否在线段上)

Lightning Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2465    Accepted Submission(s): 912 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4305 Description: There are N robots standing on the