USACO-Cow Pedigrees

来源:http://ace.delos.com/usacoprob2?a=T9Gq2i9yzJN&S=nocows

题目要求的是,用N个结点能够构造多少个高为K的二叉树,要求二叉树的结点的度为0或2。

首先,我们要关注的是树的高度和结点数。再者,这题的所有结点的度都为0或2。

考虑到结点度的特殊性,如果把高为K的树的根结点删去,则生成两个高为K-1的子树T1和T2,它们的结点数和为N-1

1.设左子树的结点数为N1,则右子树的结点数为N-N1-1;

2.设函数P表示满足题目条件的树的个数,则结果result(N)=P(N1)*P(N-N1-1);

3.由于k1的不确定性,result(N)=∑ P(N1)*P(N-N1-1)  ,其中(N1=1,3,5…,N1<=N-2)

4.对于T1和T2用同样的方法分解,很容易看到这是递归定义的,完全满足DP的两个条件:无后效性和最优子结构;
5.方程的设计:
  设F[i][j]表示高小于等于i,节点数为j的满足题目要求的树的数目,则易得:
    F[i][j]=∑F[i-1][k]*F[i-1][j-k-1]  {k=1,3,...j-2}
易得边界条件:F[i][1]=1
结果为:F[k][n]-F[k-1][n]

当然,这里的结果需要需要模一个数,而如果在DP过程中边模边算,则可能出现F[k][n]-F[k-1][n]<0的情况,解决的办法是(F[k][n]-F[k-1][n]+V)%V,V就是9901

/*
ID:ay27272
PROG:nocows
LANG:C++
*/

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>

using namespace std;

#define V 9901

int f[200][200];

int main()
{
    freopen("nocows.in","r",stdin);
    freopen("nocows.out","w",stdout);

    int n,h;
    scanf("%d%d",&n,&h);

    memset(f,0,sizeof(f));
    for (int i=1;i<=h;i++)
        f[i][1]=1;

    for (int i=1;i<=h;i++)
        for (int j=3;j<=n;j+=2)
            for (int k=1;k<=j-2;k+=2)
            f[i][j]=(f[i][j]+f[i-1][k]*f[i-1][j-k-1])%V;
    printf("%d\n",(f[h][n]-f[h-1][n]+V)%V);
    return 0;
}
posted @ 2012-11-17 00:32  ay27  阅读(159)  评论(0编辑  收藏  举报