hdu 4472 count

动态规划(递推)

选拔赛的题目,也是2012国赛的题目。题意:给n个节点,构建一棵树,使到同一层的节点所拥有的子节点数相等,问能构建出多少个

这句话,“使到同一层的节点所拥有的子节点数相等”,并没有把话说得很白,但是细想就可以发现,这句话是等同于说,这棵树是对称,而且非常对称,甚至可以想象到,以树根为轴,把树劈成两份,两边是对称的,取其中一边,再以树根劈开,两边还是对称的(这样强的对称性才满足题目说的那句话)

所以基于这点,我们可以想到,除开树根外,下面的子树(可能一棵子树,或者两棵,多棵),一定要完全相同的,为什么?哪怕每棵子树是对称的,但是子树与子树之间不同,那么都挂在树根上的时候,是不能满足  “使到同一层的节点所拥有的子节点数相等” 的。

因而问题来到这里就比较明显了,就是要找出一棵或多颗完全相同的,而且其本身也是强烈对称的子树,这不就是一个完全相同的子问题吗?因而递推就派上用场了

dp[i]=sum{ dp[j] } ( (i-1)%j==0 )  ,因为一个节点一定要用去做树根,所以剩下i-1个点,这i-1个节点把它分成几份,这几份完全相同,其本身强烈对称

 

 

总结:这题的英文本身也不好理解,能理解出中文的这句话“使到同一层的节点所拥有的子节点数相等” 是不容易的,能想到是由多颗完全相同的且其本身也完全对称的也不容易。当理解到这里,写代码已经是很容易的事情。

#include <cstdio>
#include <cstring>
#define N 1010
#define MOD 1000000007

long long dp[N];
int n;

void DP()
{
    memset(dp,0,sizeof(dp));
    dp[1]=1; dp[2]=1;
    for(int i=3; i<=1000; i++)
        for(int j=1; j<=i-1; j++)
            if((i-1)%j == 0)
                dp[i] = (dp[i]+dp[j])%MOD;
}

int main()
{
    DP();
    int ccase=0;
    while(scanf("%d",&n)!=EOF)
    {
        printf("Case %d: %lld\n",++ccase,dp[n]);
    }
    return 0;
}

 

posted @ 2013-03-10 21:26  Titanium  阅读(827)  评论(0编辑  收藏  举报