UVa 10253 (组合数 递推) Series-Parallel Networks

《训练之南》上的例题难度真心不小,勉强能看懂解析,其思路实在是意想不到。

题目虽然说得千奇百怪,但最终还是要转化成我们熟悉的东西。

经过书上的神分析,最终将所求变为:

共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 == 1 ? 1 : f[n] * 2);
36 
37     return 0;
38 }
代码君
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4319920.html