思路来源 海子 : http://www.cnblogs.com/dolphin0520/archive/2011/07/12/2103917.html
问题描述:
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,m, 输出按照此划分集合方法, 子集由m个集合组成的划分方式有几种, 如: -----inout: 4 3 ------output: 6
问题二:给出n, 输出可划分非空集合的划分方式的总数, 如: -----input: 4 -----output: 15
以上两个问题可以同时解决
---- f(n,m)表示将n个元素划分成由m个子集构成的集合的个数
case 1--------m=1时, f(n, m) = 1
case 2--------n=m时, f(n, m) = 1
case 3-------- f(n, m) = m*f(n-1, m) + f(n-1,m-1)
问题二答案就是f(n, m) 问题一就是cnt=f(n, 1) + f(n, 2) + f(n, 3) + ... + f(n, n)
#include <iostream>
#include <stdio.h>
using namespace std;
long long f[100][100];
void init()
{
// initial
for(int i = 1;i <= 99;i ++)
f[i][1] = 1;
for(int i = 2;i <= 50;i ++)
{
for(int j = 2;j <= i;j ++)
{
if(i == j)
f[i][j] = 1;
else
f[i][j] = f[i-1][j-1] + (j)*f[i-1][j];
}
}
}
int main ()
{
int n, m;
init();
//freopen("in.txt", "r", stdin);
// 问题一
while (scanf("%d %d", &n, &m) != EOF)
{
printf("%lld\n", f[n][m]);
}
// 问题二
while (scanf("%d", &n) != EOF)
{
int cnt = 0;
for(int i = 1;i <= n;i ++)
cnt += f[n][i];
printf("%lld\n", cnt);
}
}