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} 可以化为多少个不同的非空子集。
Input
Output
Sample Input
Sample Output
Source解题思路:
第二类Stirling数 S(p,k)是将p个元素的集合划分成k个不可辨别的非空盒的划分的个数。
(p个不同的小球,放入k个相同的盒子里面,不允许有空盒)
递推关系为:
S[p][0]=0 (p>=1),s[p][1]=1 (p>=0)
S[p][k]=s[p-1][k-1]+k*s[p-1][k].
注意int很容易超范围,当p等于20的时候就超出int范围类型。
代码:
#include <iostream>
#include <string.h>
using namespace std;
const int maxn=21;
typedef long long ll;
ll s[maxn][maxn];
ll ans[maxn]; //将i种不同的元素划分为0,1,2,3,...i-1种非空集合一共的总数
int n;
void init()
{
memset(s,0,sizeof(s));
memset(ans,0,sizeof(ans));
s[1][1]=1;
for(int i=2;i<=20;i++)
for(int j=1;j<=i;j++)
s[i][j]=s[i-1][j-1]+j*s[i-1][j];
for(int i=1;i<=20;i++)
for(int j=1;j<=i;j++)
ans[i]+=s[i][j];
}
int main()
{
init();
while(cin>>n)
{
cout<<ans[n]<<endl;
}
return 0;
}
[ACM] FZU 1570 集合划分问题( 不同小球放入相同盒子,第二类Stirling数),布布扣,bubuko.com
[ACM] FZU 1570 集合划分问题( 不同小球放入相同盒子,第二类Stirling数)
原文:http://blog.csdn.net/sr_19930829/article/details/38293053