【USACO2.3.2】奶牛家谱 BSOJ2086 洛谷P1472 CODEVS2053

2 篇文章 0 订阅
2086 -- 【USACO2.3.2】奶牛家谱
Description
  农民约翰准备购买一群新奶牛。 在这个新的奶牛群中, 每一个母亲奶牛都生两小奶牛。这些奶牛间的关系可以用二叉树来表示。这些二叉树总共有N个节点(3 <= N < 200)。这些二叉树有如下性质:
  (1)每一个节点的度是0或2。度是这个节点的孩子的数目。
  (2)树的高度等于K ( 1 < K < 100 )。高度是从根到任何叶子的最长的路径上的节点的数目; 叶子是指没有孩子的节点。
  有多少不同的家谱结构? 如果一个家谱的树结构不同于另一个的, 那么这两个家谱就是不同的。输出可能的家谱树的个数除以9901的余数。
Input
 第1行: 两个空格分开的整数, N 和 K
Output
 第 1 行: 一个整数,表示可能的家谱树的个数除以9901的余数。
Sample Input
5 3
Sample Output
2

这道题目显然是树形dp。
但是不同于其他的一些树形dp,此类树形dp多可以用for循环实现。
那么我们定义f[i][j]为共有i个节点共j层的子树的方案数。
所以,可以得到(根据乘法原理)
  dp[i][j]=(dp[i][j]+dp[k][j-1]*dp[i-1-k][j-1])%9901
因为必须有两个(或者0个)儿子,所以方程就是这样了。


#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#define p 9901
using namespace std;
int dp[1005][1005],N,K;
void DP()
{
    for(int j=1;j<=K;j++)
      for(int i=1;i<=N;i+=2)
        for(int k=1;k<=i-2;k++)
          dp[i][j]=(dp[i][j]+dp[k][j-1]*dp[i-1-k][j-1])%9901;
}
int main(){
	cin>>N>>K;
	for(int i=1;i<=K;i++)
	  dp[1][i]=1;
	DP();
	cout<<(dp[N][K]+9901-dp[N][K-1])%9901;
	return 0;
}

介绍一个官方解法:
求家谱总数,我们只关心树的性质是深度和节点数,所以,我们用table[i][j]表示深度为i、节点数为j的树的个数。根据给定的约束条件,j必须为奇数吗,上面介绍过了。构造一棵树当然是由更小的树来构造了。一棵深度为i、节点数为j的树可以由两个子树以及一个根结点构造而成。当i、j已经选定时,我们选择左子树的节点数k。这样我们也就知道了右子树的节点数,即j-k-1。至于深度,至少要有一棵子树的深度为i-1才能使构造出的新树深度为i。有三种可能的情况:左子树深度为i-1,右子树深度小于i-1;右子树深度为i-1,左子树深度小于i-1;左右子树深度都为i-1。事实上,当我们在构造一棵深度为i的树时,我们只关心使用的子树深度是否为i-1或更小。因此,我们使用另一个数组smalltrees[i-2][j]记录所有深度小于i-1的树,而不仅仅是深度为i-2的树。知道了上面的这些,我们就可以用以下三种可能的方法来建树了:
table[i][j] += smalltrees[i-2][k]*table[i-1][j-1-k];//左子树深度小于i-1,右子树深度为i-1
table[i][j] += table[i-1][k]*smalltrees[i-2][j-1-k];//左子树深度为i-1,右子树深度小于i-1
table[i][j] += table[i-1][k]*table[i-1][j-1-k];//左右子树深度都为i-1另外,如果左子树更小,我们可以对它进行两次计数,因为可以通过交换左右子树来得到不同的树。总运行时间为O(K*N^2),且有不错的常数因子。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值