[USACO Section 2.3] Cow Pedigrees (动态规划)

题目链接


Solution

我DP太菜啦...
考虑到一棵二叉树是由根节点以及左儿子和右儿子构成。
所以答案其实就是 左儿子方案数*右儿子方案数 。

状态定义:
\(f[i][j]\) 代表深度为 \(i\) ,节点个数为 \(j\) 的二叉树方案数。

转移方程:
对于每一个状态,节点总数已经确定。
那么枚举一维左子树的节点个数,右边用总数减去。

如果要构建一棵深度为 \(i\) 的二叉树,则两棵子树中必有一棵深度为 \(i-1\)
此时有三种情况:

  1. 左子树深度小于 \(i-1\),右子树深度为 \(i-1\)
  2. 右子树深度小于 \(i-1\),左子树深度为 \(i-1\)
  3. 两边子树深度均为 \(i-1\)

由于我们需要的是深度小于 \(i-1\) 的所有情况,所以记录一个前缀和 \(sum\)
每一次要加上的便是 \(sum_{i-2}\)

然后参照以上做即可。

Code

#include<bits/stdc++.h>
using namespace std;
const int mod=9901;
int f[110][210],n,k,sum[110][210];

int main()
{
    scanf("%d%d", &n, &k);
    f[1][1]=1;
    for (int i=2;i<=k;i++)
        for (int j=1;j<=n;j++)
        {
            for (int p=1;p<j;p++)
            {
                f[i][j]=(f[i][j]+sum[i-2][p]*f[i-1][j-p-1])%mod;
                f[i][j]=(f[i][j]+sum[i-2][j-p-1]*f[i-1][p])%mod;
                f[i][j]=(f[i][j]+f[i-1][p]*f[i-1][j-p-1])%mod;
            }
            sum[i-1][j]=(sum[i-2][j]+f[i-1][j])%mod;
        }
    printf("%d\n", f[k][n]);

    return 0;
}

posted @ 2018-09-14 16:49  Kevin_naticl  阅读(182)  评论(0编辑  收藏  举报