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