题目描述:给定正整数n,计算出n个元素的集合{1,2,3,... n }可以划分为多少个不同的非空子集。
解题的思路:把n个元素编号,对于最后那个n号元素,有两种情况:
一种是独立组成一个集合,另一种是和别的元素混在一起。
对于第一种情况,等价于把前n-1个元素分成m-1份,然后n号元素单独放。
对于第二种情况,等价于把前n-1个元素分成m份,然后把n号元素放入这m个集合中的一个(有m种放法)
总数就是 F(n,m) =F(n-1,m-1) + m * F(n-1,m)
考虑几种极端的情况,
m=n的情况,结果很明显是1。
m=1的情况,结果也是1。
n=1的情况,m只能等于1, 结果也是1。
关键代码:
int f(int n, int m)
{
if (m > n || m == 0)
return 0;
if (n == 1 || m == 1 || m == n)
return 1;
return m * f(n-1, m) + f(n-1, m-1);
}
// 动态规划
void stirlingNumber2(int n, int m)
{
int [][] dp = new int[n+1][n+1];
dp[0][0] = 1;
int min = 0;
int i, j;
// 非空子集0个
for (i=1; i<=n; i++)
dp[i][0] = 0;
// m > n
for (i=0; i<n; i++)
dp[i][i+1] = 0;
for (i=1; i<=n; i++)
{
min = i < m ? 0 : m;
for (j=1; j<=m; j++)
{
dp[i][j] = j * dp[i-1][j] + dp[i-1][j-1];
System.out.println("dp["+i+"]["+j+"]" + dp[i][j]);
}
}
System.out.println(dp[n][m]);
}