时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0

题型: 编程题 语言: G++;GCC;VC;JAVA
教材课后习题2-8
n个元素的集合{1,2,…,n}可以划分若干个非空子集。例如,当n=4时,集合{1,2,3,4}可以划分为15个不同的非空子集如下:
{{1},{2},{3},{4}},
{{1,2},{3},{4}},
{{1,3},{2},{4}},
{{1,4},{2},{3}},
{{2,3},{1},{4}},
{{2,4},{1},{3}},
{{3,4},{1},{2}},
{{1,2},{3,4}},
{{1,3},{2,4}},
{{1,4},{2,3}},
{{1,2,3},{4}},
{{1,2,4},{3}},
{{1,3,4},{2}},
{{2,3,4},{1}},
{{1,2,3,4}}
给定正整数n(1<=n<=20),计算出n个元素的集合{1,2,…,n} 可以化为多少个由m个不同的非空子集组成的集合。
两个整数n和m。
集合划分的数量。
注意此类问题数据较大,需要使用long long 类型。
4 3
6
递归思路:以最大数n为例
以集合元素个数为4为例,我们来看应该怎么求解集合划分问题。因为我们采用的是分治策略,因此,我们先看集合元素个数为3的集合的划分
考虑3个元素的集合,可划分为
因此 F(3, 1) = 1; F(3, 2) = 3; F(3, 3) = 1;
如果我们要求4个元素的集合划分为2个子集的集合的个数F(4,2),求解过程如下:
即如果有 m 个子集,那么该情况的个数为 m * F(n - 1, m)
即在 F(n - 1, m - 1) * 1
所以:F(4, 2)= 2 * F(3, 2)+ F(3, 1)
由以上的演示可以得出集合划分的公式如下:

此式中n为元素个数,m为子集个数。
更多注释可查看下方的完整代码中,有助于理解
#include using namespace std;
/*
20 10
5917584964655
*/long long f(int n,int m)
{// 递归结束条件,n和m相等,即此时每个集合只有一个元素,因为比如4个元素最多只能划分为4个集合,或只划分为1个集合if(n == m || m == 1) {return 1;} else {return f(n - 1, m - 1) + m * f(n - 1, m);}}int main()
{int n, m;cin >> n >> m;cout << f(n, m) << endl;return 0;
}
对我感兴趣的小伙伴可查看以下链接