生成树计数算法

生成树计数问题:给出一个无向图,求它的生成树的个数。
预备知识

(1)一个n个顶点的无向图G,定义它的度数矩阵D,D是一个n*n的矩阵。对于顶点u,设度数为deg[u],如果i=j,那么D[i][j]=deg[i],否则D[i][j]=0.

(2)一个n个顶点的无向图G,定义它的邻接矩阵A,A是一个n*n的矩阵。如果i和j之间有边,那么A[i][j]=1,否则等于0。

(3)一个n个顶点m条边的无向图G,定义它的关联矩阵B,B是一个n*m的矩阵。对于第i条边e[i]=(u,v),那么B[u][i]和B[v][i]中一个是1,一个是-1,第i列其他值为0。那么我们有

所以对于

如果i=j,它是顶点i的度数,否则,如果i和j之间有边,那么它等于-1,否则它等于0.

(4)对于一个n个顶点m条边的无向图G,定义它的Kirchhoff矩阵C,C是一个n*n的矩阵,

很显然,C=D-A

Matrix-Tree定理

对于一个无向图G,它的生成树个数等于其Kirchhoff矩阵任何一个n-1阶主子式的行列式的绝对值。 所谓n-1阶主子式,就是对于任意一个r,将C的第r行和第r列同表示时删去后的新矩阵,用下面的字母表示$C_{r}$

接下来,我们首先证明下面四个性质:

性质1:对于任何一个图的Kirchhoff矩阵C,它的行列式为0。

性质2:对于不连通的图,它的Kirchhoff矩阵C的任一个n-1阶主子式的行列式均为0。

性质3:如果G是一棵树,它的Kirchhoff矩阵C的任一个n-1阶主子式的行列式均为1。

性质4:柯西-比内公式。设A和B分别是n*m和m*n的矩阵,那么

其中S是一个子集,大小为n,也就是S取遍所有的n子集,相应的As和Bs为从A和B中取出S元素下标的所有列和所有行。

性质1证明:由C的性质可得,它的每一行每一列和均为0,那么我们把第2到第n行都加到第一行,那么第一行就全部是0了。有一行全部是0,那么它的行列式就是0了。

性质2证明: 假设G中存在k(k>1)个连通分量G1,G2,,,,,Gk,那么,我们可以重新安排C的行和列使得属于G1的顶点首先出现,然后是G2等。显然,行和列都要交换,所以进行了偶数次交换。所以,行列式的符号没有改变。 交换后是下面这个样子:

设r是Gi中的第j行,那么

性质3证明:这里给出一个构造的方法,使得矩阵$C_{r}$通过一系列变换,成为上三角矩阵,且对角线全部是1。第一步,将r看做树根,将所有点按照距离顶点r的距离升序排序,距离相同的随便排。第二步,重新编号 n-1个顶点,距离r越近的点编号越小,Cr这个矩阵也按照重新编号后的顺序重新排列。第三步,对于以r为根的树,设j是i的父亲(父亲是r的就不用管了),那么将第i列加到第j列上。 最后我们来说明,现在的Cr是对角线为1的上三角矩阵,也就是说明对于每一列x,第x个元素下面都是0,第x个元素是1。首先最后一列即n-1列满足,因为它下面没有元素了。我们来看第x列,它的孩子所在的列都在它的后面。它的孩子,不妨设有三个a,b,c,满足了第a列第a个元素下面都是0,第a个元素是1,第b列第b个元素下面都是0,第b个元素是1,第c列第c个元素下面都是0,第c个元素是1 。而第x列第x个元素下面的第a,b,c正好都是-1,a,b,c列加过来之后变成0了,而第x个元素原来是4(除了三个孩子外,它还有父亲),而第a,b,c列的第x个元素都是-1,加过来之后就是4-3=1了。证毕。

性质4:我不会证明这个。

有了上面四条性质,来证明Matrix-tree定理:

我们看到,S枚举了所有的n-1子集,那么对于

如果S枚举的n-1子集是一个生成树,它的值为1,否则它为0。所以$det(C_{r})$就是生成树的个数。

时间: 2024-10-12 23:31:47

生成树计数算法的相关文章

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

生成树计数

生成树计数就是统计一张图中一共有多少种构造生成树的方案. 大概要用到组合数学等等的数学知识. 以下内容均来自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跑

【生成树计数】专题总结

在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

bzoj1002 生成树计数 找规律

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

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的不同生成树的个数等于其

javaVM 判断对象实例何时回收 用的可达性分析算法,而非引用计数算法

做java开发也好几年了,今天才晓得java内存的回收算法,真是惭愧惭愧 java虚拟机判断一个对象实例是否可以被回收,并非引用计数算法. 因为引用计数算法很难解决对象直接互相循环引用的问题. 所以java C#都是使用可达性分析来判断对象是否可以回收的. 这个算法的基本思路就是通过一系列的称为"GC Root"的对象作为起始点,从这些节点开始向下搜素,搜索所走过的路径称为应用链,当一个对象到GC Roots没有任何引用链相连时.则证明此对象时不可用的,可以被回收了.如下图对象obje

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-