usaco Cow Pedigrees

这又是一道典型的dp问题,其表观特点在于难以下手,解决这类问题重要的一点是,一定要考虑清楚状态转移方程的含义,不要为追求简洁而丧失错误性。

我们来详细的分一下,这个问题的动态规划过程。

首先是观察树的结构特点,每一课深度为i的树都可以由两颗子树加上一个根节点构成。由此来考虑递推的过程,我们想要知道节点数和深度确定的树的个数。

设其深度为i,节点数为j,去掉根节点,节点数变为j-1,所以两颗子树节点数之和为j-1,我们假设其中一个为k,另一个则是j-k-1。

现在能否保证两颗子树合成后的深度为i呢

如果要这样,那么至少有一棵子树其深度达到i-1

大致的写出转移方程

dp【i】【j】=求和(dp【i-1】【k】*dp【深度<i-1】【j-k-1】*2+dp【i-1】【k】*dp【i-1】【k】)

能不能再简化一下呢?

第一个办法,求dp【i】【j】的同时把dp【深度<i-1】【j-k-1】递推地求出来。

建立dp【深度<i-1】【j-k-1】=subtree【i-2】【j-k-1】=subtree【i-3】【j-k-1】+dp【i-2】【j-k-1】;

标程:

 table[1][1]=1;
    for (int i=2;i<=K;i++) {
        for (int j=1;j<=N;j+=2)
            for (int k=1;k<=j-1-k;k+=2) {
                if (k!=j-1-k) c=2; else c=1;    
                table[i][j]+=c*(
                        smalltrees[i-2][k]*table[i-1][j-1-k]  // left subtree smaller than i-1
                        +table[i-1][k]*smalltrees[i-2][j-1-k]  // right smaller
                        +table[i-1][k]*table[i-1][j-1-k]);// both i-1
                table[i][j]%=MOD;
            }
        for (int k=0;k<=N;k++) {          // we ensure that smalltrees[i-2][j] in the next i
            smalltrees[i-1][k]+=table[i-1][k]+smalltrees[i-2][k]; // iteration contains the number
            smalltrees[i-1][k]%=MOD;           // of trees smaller than i-1 and with j nodes
        }
    }
    

第二个办法

这里需要改变一下dp【i】【j】的含义,变为深度<=i,节点数为j的树的个数。

那么dp【i】【j】=dp【i-1】【k】*dp【i-1】【j-k-1】;

这样求出dp【i】【j】-dp【i-1】【j】就是最后的结果。

关键问题来了,如何确定状态的转移顺序?

我们可以先枚举深度i,在对于每个i,累加i-1各个节点数的dp值。

可以先枚举节点数吗?也是可以的。请想清楚这一点。

可以转化成一维数组吗?

答案是不可以,原因在于对于第2项的递推过程不能保证状态的顺序性。它是由两边向中间的的相乘。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值