USACO 2.3.2 Cow Pedigrees 解题报告
分类:DP
作者:ACShiryu
时间:2011-7-17
Cow Pedigrees
Silviu Ganceanu -- 2003
Farmer John is considering purchasing a new herd of cows. In this new herd, each mother cow gives birth to two children. The relationships among the cows can easily be represented by one or more binary trees with a total of N (3 <= N < 200) nodes. The trees have these properties:
- The degree of each node is 0 or 2. The degree is the count of the node's immediate children.
- The height of the tree is equal to K (1 < K <100). The height is the number of nodes on the longest path from the root to any leaf; a leaf is a node with no children.
How many different possible pedigree structures are there? A pedigree is different if its tree structure differs from that of another pedigree. Output the remainder when the total number of different possible pedigrees is divided by 9901.
PROGRAM NAME: nocows
INPUT FORMAT
- Line 1: Two space-separated integers, N and K.
SAMPLE INPUT (file nocows.in)
5 3
OUTPUT FORMAT
- Line 1: One single integer number representing the number of possible pedigrees MODULO 9901.
SAMPLE OUTPUT (file nocows.out)
2
OUTPUT DETAILS
Two possible pedigrees have 5 nodes and height equal to 3:
@ @ / \ / \ @ @ and @ @ / \ / \ @ @ @ @
题目意思很简单,就是给出N和K,找出满足只有N个节点,并且每个节点的度为0或2,深度为K的二叉树的总数。
很显然可以的得到这个公式 a[i+j+1][max(h1+h2)+1]+=a[i][h1]*a[j][h2];
四个循环就可以解决,求出a[N][K];
但要注意a[i][h1]*a[j][h2]和a[j][h2]*a[i][h1]是一样的,所以我们不妨设i>=j,h1>=h2;
则可以解决问题
还要注意临界情况,当i=j或者h1=h2出现时
数据分许:时间复杂度为O(n^2*k^2),题目还可发现当n为偶数时,题目的答案是0又题目中n和k的数据不是很大,每次循环都是加2,故应该不会超时
参考代码:
1 /*
2 ID:shiryuw1
3 PROG:nocows
4 LANG:C++
5 */
6 #include<iostream>
7 #include<cstdlib>
8 #include<cstdio>
9 #include<cstring>
10 #include<algorithm>
11 #include<cmath>
12 using namespace std;
13 int a[222][111]={0};//表示i个节点构造题目要求的深度为j的二叉树的个数
14 int main()
15 {
16 freopen("nocows.in","r",stdin);
17 freopen("nocows.out","w",stdout);
18 int n,m;
19 int i,j,h1,h2;
20 cin>>n>>m;
21 a[1][1]=1; //1个节点构造深度为一的二叉树只有1中情况
22 for(i=1;i<=n;i+=2)
23 { //i代表左子树的节点数,故要小于n
24 for(j=1;j<=i&&i+j<n;j+=2)
25 { // j代表右子树的节点数,故要i+j<n
26 //又由分析,左右可以交换,故规定j<=i
27 for(h1=1;h1<m;h1++)
28 { //h1表示左子树的深度,可知;h1<m
29 for(h2=1;h2<=h1;h2++)
30 { //h2表示右子树的深度,又左右可以交换,故规定;h2<=h1
31 int ii=i+j+1; //左右子树的节点加上根节点
32 int h=h1+1;//由规定知h1>=h2,故h=max{h1,h2}+1=h1+1
33 if(i==j&&h1==h2)
34 //如果有i=j和h1=h2,则不能交换左右子树
35 a[ii][h]=((a[ii][h]+a[i][h1]*a[j][h2]))%9901;
36 else if(h1==h2||i==j)
37 //当只有h1=h2或i=j时可以交换左右子树的节点数
38 a[ii][h]=(a[ii][h]+2*a[i][h1]*a[j][h2])%9901;
39 else
40 //否则既要交换i和j也要交换左右深度a[ii][h]=(a[ii][h]+2*a[i][h1]*a[j][h2]+2*a[i][h2]*a[j][h1])%9901;
41 }
42 }
43 }
44 }
45 cout<<a[n][m]<<endl; //输出n个节点构造shendu为m的满足条件的二叉树个数
46 return 0;
47 }
作者:ACShiryu
出处:http://www.cnblogs.com/ACShiryu/
若非注明,本博客文章均为原创,版权归作者和博客园共有,欢迎转载,但必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
该文章也同步发布在我的新浪微博中-ACShiryu's weibo,欢迎收听。