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; }