标签:
《训练之南》上的例题难度真心不小,勉强能看懂解析,其思路实在是意想不到。
题目虽然说得千奇百怪,但最终还是要转化成我们熟悉的东西。
经过书上的神分析,最终将所求变为:
共n个叶子,每个非叶节点至少有两个子节点的 树的个数f(n)。最终输出2 × f(n)
首先可以枚举一下根节点的子树的叶子个数,对于有i个叶子的子树,共有f(i)种,
设d(i, j)表示每棵子树最多有i个叶节点,一共有j个叶节点的方案数。
所求答案为d(n-1, n)
假设恰好有i个叶子的子树有p棵,因为每个子树互相独立,所以对于p个有i个叶子的子树,共有C(f(i)+p-1, p)种情况,重复元素的全排列。
d(i, j) = sum{C(f(i)+p-1, p) × d(i-1, j-p×i) | p >= 0 且 p×i <= j }
边界:
d(i, 0) = d(i, 1) = 1 (i >= 1), d(0, 0) = 1
1 #include <cstdio> 2 3 const int maxn = 30; 4 long long d[31][31], f[31]; 5 6 long long C(long long n, long long m) 7 { 8 long long ans = 1; 9 if(m > n - m) m = n - m; 10 for(int i = 0; i < m; i++) 11 { 12 ans *= n - i; 13 ans /= i+1; 14 } 15 return ans; 16 } 17 18 int main() 19 { 20 f[1] = 1; 21 int n = maxn; 22 d[0][0] = 1; 23 for(int i = 1; i <= n; i++) d[i][0] = d[i][1] = 1; 24 for(int i = 1; i <= n; i++) 25 { 26 for(int j = 2; j <= n; j++) 27 { 28 for(int p = 0; p * i <= j; p++) 29 d[i][j] += C(f[i]+p-1, p) * d[i-1][j-p*i]; 30 } 31 f[i+1] = d[i][i+1]; 32 } 33 34 while(scanf("%d", &n) == 1 && n) 35 printf("%lld\n", n == 1 ? 1 : f[n] * 2); 36 37 return 0; 38 }
UVa 10253 (组合数 递推) Series-Parallel Networks
标签:
原文地址:http://www.cnblogs.com/AOQNRMGYXLMV/p/4319920.html