从Prufer编码到各种树的计数

P r u f e r Prufer Prufer编码到各种树的计数

1. P r u f e r Prufer Prufer编码

  1. 无根树进行编码的一种方式,无根树就是边没有方向的树,即以树上的每一个点做根,只算一种方案。

  2. 无根树转序列做法

    ​ 每次找到编号最小的叶子,输出它父亲的编号,然后删除,直到只剩2个节点。

    1. 序列转无根树做法

    ​ 设集合 S = { 1 , 2 , ⋯   , n } S=\left \{ 1,2,\cdots,n \right \} S={1,2,,n}

    ​ 第 i i i次,找到在 S S S中没有在 p r u f e r prufer prufer编码第 i i i n − 2 n-2 n2位出现的最小的数,将它与 p r u f e r prufer prufer编码的第 i i i位连边,并把它从S中删除。

    ​ 最后剩下的两个数,它们两个连一条边即可。

    ​ 代码实现的时候,可以将每个点的度数初始化为 p r u f e r prufer prufer序列中出现的次数+1,每次找度数为1最小的那一个与 p r u f e r prufer prufer序列当前位连边。

2. 有标号无根树的计数( C a y l e y Cayley Cayley公式)

  1. 由上面的做法显然可以得出,每一个长度为n-2的序列,唯一的对应了一棵无根树,且一颗无根树唯一的对应了一个序列。

  2. 因此可以得到n个点的有标号无根树总共有 n n − 2 n^{n-2} nn2个。

  3. 性质与应用

    1. p r u f e r prufer prufer编码中,每个点出现的次数为 该 点 度 数 − 1 该点度数-1 1

    2. 如果限制n个点的读数为 d 1 , d 2 , d 3 , ⋯   , d n d_1,d_2,d_3,\cdots,d_n d1,d2,d3,,dn,那么这样的无根树共有
      ( n − 2 ) ! ( d 1 − 1 ) ! ( d 2 − 1 ) ! ( d 3 − 1 ) ! ⋯ ( d n − 1 ) ! 个 \frac {(n-2)!}{(d_1-1)!(d_2-1)!(d_3-1)!\cdots(d_n-1)!}个 (d11)!(d21)!(d31)!(dn1)!(n2)!

  4. 如果只限制了k个呢, p r u f e r prufer prufer编码剩了m个位置呢?那么假装限制了,再乘以随便填的方案数,即
    ( n − 2 ) ! ( d 1 − 1 ) ! ( d 2 − 1 ) ! ⋯ ( d k − 1 ) ! ( m ) ! ∗ ( n − k ) m \frac {(n-2)!}{(d_1-1)!(d_2-1)!\cdots(d_k-1)!(m)!}*(n-k)^m (d11)!(d21)!(dk1)!(m)!(n2)!(nk)m

3. 有标号有根树的计数

  1. p r u f e r prufer prufer编码是无根树,但是树形均不同,那么每个生成的树以每个点做根均可,因此共有
    n n − 2 ∗ n = n n − 1 个 n^{n-2}*n=n^{n-1}个 nn2n=nn1

4.无标号有根树的计数

  1. 方法1朴素形式,设 a n a_n an为树大小为n时的答案。设对于根,大小为k的子树共有 c k c_k ck个,而每个子树都可以选择 1 ∼ a k 1\sim a_k 1ak的一种方案,即 ∑ k = 1 a k x k = c k \sum_{k=1}^{a_k}x_k=c_k k=1akxk=ck,该方程非负整数解个数为 ∏ k > 0 C a k + c k − 1 c k \prod_{k>0}C_{a_k+c_k-1}^{c_k} k>0Cak+ck1ck( a 1 = 1 a_1=1 a1=1)。
    a n = ∑ c 1 + 2 c 2 + ⋯ + n c n = n − 1 ∏ k > 0 C a k + c k − 1 c k a_n=\sum_{c_1+2c_2+\cdots+nc_n=n-1}\prod_{k>0}C_{a_k+c_k-1}^{c_k} an=c1+2c2++ncn=n1k>0Cak+ck1ck

  2. 方法1高级形式经过复杂的母函数推导,我们得到
    令 s n , j = ∑ 1 ≤ i ≤ n j a n + 1 − i ∗ j , 则 有 s n , j = s n − j , j + a n + 1 − j 则 有 a n + 1 = ∑ 1 ≤ j ≤ n j a j s n , j n 令s_{n,j}=\sum_{1\leq i \leq \frac n j}a_{n+1-i*j},则有s_{n,j}=s_{n-j,j}+a_{n+1-j}\\ 则有a_{n+1}=\frac {\sum_{1\leq j \leq n}ja_js_{n,j}} {n} sn,j=1ijnan+1ij,sn,j=snj,j+an+1jan+1=n1jnjajsn,j

  3. 方法2朴素形式如果我们把定义改为 f n , j f_{n,j} fn,j表示树大小为n,根节点度数为j的方案数,那么 a n = ∑ j = 1 n f n , j a_n=\sum_{j=1}^nf_{n,j} an=j=1nfn,j,就有
    f i , j = ∑ c 1 + 2 c 2 + ⋯ + j c j = i − 1 ∏ k > 0 j C a k + c k − 1 c k f_{i,j}=\sum_{c_1+2c_2+\cdots+jc_j=i-1}\prod_{k>0}^jC_{a_k+c_k-1}^{c_k} fi,j=c1+2c2++jcj=i1k>0jCak+ck1ck

  4. 方法2高级形式我们考虑对 f i , j f_{i,j} fi,j进行 d p dp dp,可以通过限制最大子树进行背包,即从小到大枚举 m a x s o n maxson maxson,则有
    f i , j = ∑ k = 1 m a x { j , ⌊ i m a x s o n ⌋ } C a m a x s o n + k − 1 k f i − k ∗ m a x s o n , j − k f_{i,j}=\sum_{k=1}^{max\left\{j,\lfloor\frac i {maxson\rfloor}\right\}}C_{a_{maxson}+k-1}^k f_{i-k*maxson,j-k} fi,j=k=1max{j,maxsoni}Camaxson+k1kfikmaxson,jk

  5. 这样有一个好处就是可以限制最大度数,如构造烷烃。

5.无标号无根树的计数

  1. 利用一下上题的 a n a_n an

  2. 方法1,设 b n b_n bn为本题的答案,根据质心的关系,可以得到
    n 为 奇 数 时 b n = a n − ∑ 0 < i ≤ ⌊ n 2 ⌋ a i a n − i n 为 偶 数 时 b n = a n − ∑ 0 < i ≤ n a i a n − i + 1 2 a n 2 ( a n 2 + 1 ) n为奇数时\\b_n=a_n-\sum_{0<i\leq \lfloor\frac n 2\rfloor}a_ia_{n-i}\\n为偶数时\\b_n=a_n-\sum_{0<i\leq n}a_ia_{n-i}+\frac 1 2 a_{\frac n 2}(a_{\frac n 2}+1) nbn=an0<i2naianinbn=an0<inaiani+21a2n(a2n+1)

  3. 方法2,可以通过枚举重心的方法来解决,强制 m a x s o n < ⌈ n 2 ⌉ maxson<\lceil\frac n 2 \rceil maxson<2n,则保证是是以重心为根的无标号有根树计数,但如果n为偶数,可能会有两个重心,这两个重心子树大小都是 n 2 \frac n 2 2n,因此最终结果为
    a n s = ∑ j = 0 m f n , j + [ n   m o d   2   = 0 ] C a n 2 + 1 2 ans=\sum_{j=0}^mf_{n,j}+[n\ mod\ 2\ =0] C_{a_{\frac n 2 +1}}^2 ans=j=0mfn,j+[n mod 2 =0]Ca2n+12

  4. 烷烃例题 [BZOJ4271]chemistry,方法2(没有加高精度)代码如下

    //无高精度版本 
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define maxn 505
    using namespace std;
    typedef long long ll;
    int n,m;
    ll dp[maxn][maxn];
    ll c(ll n,ll m)
    {
    	ll ans=1;
    	for(int i=m;i>=1;i--)
    	{
    		ans=ans*n;
    		n--;
    	}
    	for(int i=m;i>1;i--)
    	{
    		ans/=i;
    	}
    	return ans;
    }
    int main()
    {
    	dp[1][0]=1;
    	scanf("%d",&n); m=4;
    	for(int maxson=1;maxson<((n+1)/2);maxson++)
    	{
    		ll a=0;
    		for(int j=0;j<m;j++) 
    			a+=dp[maxson][j];
    		for(int i=n;i>maxson;i--)
    		{
    			for(int j=1;j<=m;j++)
    			{
    				for(int k=1;k<=j&&maxson*k<i;k++)
    				{
    					dp[i][j]+=dp[i-maxson*k][j-k]*c(a+k-1,k);
    				}
    			}
    		}
    	}
    	ll ans=0;
    	for(int j=0;j<=m;j++)
    		ans+=dp[n][j];
    	if(!(n&1))
    	{
    		ll a=0;
    		for(int j=0;j<m;j++)
    			a+=dp[n/2][j];
    		ans+=c(a+1,2);
    	}
    	printf("%lld\n",ans);
    }
    

参考资料

  1. 顾誉州WC交流https://wenku.baidu.com/view/3fbabbcc647d27284a735113.html
  2. 华师一附中赵爽论文 https://max.book118.com/html/2018/0403/159821895.shtm
  3. Flashhu https://www.cnblogs.com/flashhu/p/9457830.html
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值