【9409】集合的划分问题

Time Limit: 3 second
Memory Limit: 2 MB

问题描述:
  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}} 
其中,集合{{1,2,3,4}} 由1 个子集组成;集合{{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}} 由2 个子集组成;集合{{1,2},{3},{4}},{{1,3},{2},{4}},{{1,4}, {2},{3}},{{2,3},{1},{4}},{{2,4},{1},{3}},{{3,4},{1},{2}} 由3 个子集组成;集合{{1},{2},{3},{4}} 由4 个子集组成。 
编程任务:
  给定正整数n 和m,计算出n 个元素的集合{1,2,., n }可以划分为多少个不同的由m 个非空子集组成的集合。
>

Input

输入文件仅一行,输入元素个数n 和非空子集数m。

Output

将计算出的不同的由m个非空子集组成的集合数

Sample Input

4 3

Sample Output

6

【题解】

对于集合的第n个元素。它有两种情况。第一种,自身一个元素作为集合。第二种,与其他元素合在一个集合中。

对于第一种情况。问题转化为n-1个元素。划分为m-1个集合的情况。

对于第二种情况。问题转化为n-1个元素。划分为m个集合的情况。然后第n个元素可以加入到前n-1个元素组成的m个集合中的任意一个集合。

即f[n][m] = f[n-1][m-1]+f[n-1][m]*m;

当n==m时f[n][m] = 1;

当m>n时,f[n][m]=0;

当m < 1时,f[n][m]==0(当然 如果n==m==0则f[n][m] = 1)

不用担心这样组成的集合会重复。

因为只有后面的元素才会主动去找前面的元素构成集合。前面的元素是不会主动找到后面的元素的!这就满足了组合的定义。

假设x<y;

y选择与前面的元素构成集合。

x选择自身一个元素。

那么这时x就不是自身一个了。可以是x和y在一起。

但是不用担心x不能选择自身一个。

因为y也可以选择是自身一个。这种情况下。

x也就可以选择自身一个了。

就这样吧。不要去钻牛角尖。要大胆地想。

【代码】

#include <cstdio>

int nn, mm;

void input_data()
{
	scanf("%d%d", &nn, &mm);
}

__int64 stirling(int n, int m)
{
	if (n < m) //如果m大于n了。那就更不可能了。3个元素无法划分为100个集合!
		return 0;
	if (n == m) //n个元素划分为n个集合。那就是所有元素都变成一个。。
		return 1;
	if (m < 1) //如果n个元素划分为0个集合,因为n大于0,所以这是不合理的。
		return 0;
	return stirling(n - 1, m - 1) + stirling(n - 1, m)*m; //根据递归式写递归程序。
}

int main()
{
	input_data();
	printf("%I64d", stirling(nn, mm)); //数字可能较大所以用了int64类型
	return 0;
}


原文地址:https://www.cnblogs.com/AWCXV/p/7632318.html