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