【noi 2.6_9281】技能树(DP)
题意:要求二叉树中每个节点的子节点数为0或2,求有N个节点高度为M的不同的二叉树有多少个(输出 mod 9901 后的结果)。
解法:f[i][j]表示高度为i的有j个节点的二叉树个数。同上题一样,把高度为i的树分解成1个根节点和2棵子树,子树中有一棵高度为i-1,较高,枚举其结点数,另一颗较矮,高度为0~i-2(用sum存),结点数也可知道了。分别左子树和右子树较高,便*2。还有2子树一样高,同为i-1时的情况。
==》也可转化为一棵高i-1,另一棵高0~i-1,*2后减去多算的两子树同高 i-1 的情况。
注意——循环可限制大小时,不要轻易缩小该循环范围。因为缩小后没有提到的那几个状态要想清楚后另外赋值。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 #define N 310 7 #define M 110 8 #define mod 9901 9 10 int f[M][N],sum[N][M]; 11 int main() 12 { 13 int n,m; 14 scanf("%d%d",&n,&m); 15 f[1][1]=sum[1][1]=1; 16 for (int j=2;j<=n;j++) 17 f[1][j]=sum[1][j]=0; 18 for (int i=2;i<=m;i++) 19 { 20 for (int j=1;j<=n;j++) 21 { 22 f[i][j]=0; 23 for (int k=1;k<j;k++) 24 f[i][j]=(f[i][j]+(2*f[i-1][k]*sum[i-1][j-k-1]-f[i-1][k]*f[i-1][j-k-1])%mod)%mod; 25 sum[i][j]=(sum[i-1][j]+f[i][j])%mod; 26 } 27 } 28 printf("%d\n",f[m][n]); 29 return 0; 30 }