#include
<
stdio.h
>
/* ***************************************************************** */
/* 整数划分问题:
**将正整数n表示成一系列正整数之和:n=n1+n2+…+nk,
**其中n1>=n2>=…>=nk>=1,k>=1。
**正整数n的这种表示称为正整数n的划分。求正整数n的不同划分个数。
**例如:正整数6有如下11种不同的划分:
**6;
**5+1;
**4+2,4+1+1;
**3+3,3+2+1,3+1+1+1;
**2+2+2,2+2+1+1,2+1+1+1+1;
**1+1+1+1+1+1。
*/
/* ********************************************************************** */
/* ********************************************************************** */
/* 算法:
**记q(n,m)表示n的最大加数n1不大于m的划分个数,则有:
** |- 1 ,n=1,m=1
**q(n,m)=| q(n,n) ,n<m
** | 1+q(n,n-1),n=m ,n的划分由n1=n的划分和n1<=n-1的划分组成
** |_ q(n-m,m)+q(n,m-1),n>m>1,n的最大加数n1不大于m的划分由n1=m的划分和n1<=m-1的划分组成
*/
/* ***************************************************************** */
int int_partion( int n, int m)
{
if (n == 1 || m == 1 )
return 1 ;
else if (n < m)
return int_partion(n,n);
else if (n == m)
return 1 + int_partion(n,n - 1 );
else
return int_partion(n - m,m) + int_partion(n,m - 1 );
}
/* 非递归算法 */
#define N 6
int S[N + 1 ][N + 1 ];
int int_partion_2( int n, int m)
{
int i,j;
for (i = 1 ;i <= n;i ++ )
{
S[i][ 1 ] = 1 ;
S[ 1 ][i] = 1 ;
}
for (i = 2 ;i <= n;i ++ )
{
for (j = 2 ;j <= m;j ++ )
{
if (i == j)
S[i][j] = 1 + S[i][i - 1 ];
else if (i < j)
S[i][j] = S[i][i];
else
S[i][j] = S[i - j][j] + S[i][j - 1 ];
}
}
return S[n][m];
}
/* ***************************************************************** */
/* 集合划分问题:
**n个元素{1,2,,n}可以划分为多少个非空子集。该值实际上为Bell数,记为B(n)。
**例如:{1,2,3}的划分:
**{{1,2,3}}, {{1,2},{3}}, {{1,3},{2}}, {{1},{2,3}}
*/
/* ***************************************************************** */
/* ********************************************************************** */
/* 算法:
**记s(n,m)表示n个元素集合可以划分为m个非空子集的数量,该数实际上是Stirling数,则有:
**s(n,m)=m*s(n-1,m)+s(n-1,m-1); s(n,n+1)=0,s(n,0)=0,s(0,0)=1。
**显然:B(n)=s(n,1)+s(n+2)++s(n,n)
*/
/* ***************************************************************** */
// 计算stirling数
int stirling( int n, int m)
{
int min,i,j;
S[ 0 ][ 0 ] = 1 ;
for (i = 1 ;i <= n;i ++ )
S[i][ 0 ] = 0 ;
for (i = 0 ;i < n;i ++ )
S[i][i + 1 ] = 0 ;
for (i = 1 ;i <= n;i ++ )
{
if (i < m)
min = i;
else
min = m;
for (j = 1 ;j <= min;j ++ )
S[i][j] = j * S[i - 1 ][j] + S[i - 1 ][j - 1 ];
}
return S[n][m];
}
// 计算bell数
int bell( int n)
{
int num = 0 ;
stirling(n,n);
for ( int i = 1 ;i <= n;i ++ )
{
num += S[n][i];
}
return num;
}
int main()
{
int n = 4 ,m = 2 ;
// printf("%d pation numbers are:%d\n",n,int_partion_2(n,n));
printf( " %d,%d sirling number is:%d\n " ,n,m,stirling(n,m));
printf( " %d bell number is:%d\n " ,n,bell(n));
return 0 ;
}
/* ***************************************************************** */
/* 整数划分问题:
**将正整数n表示成一系列正整数之和:n=n1+n2+…+nk,
**其中n1>=n2>=…>=nk>=1,k>=1。
**正整数n的这种表示称为正整数n的划分。求正整数n的不同划分个数。
**例如:正整数6有如下11种不同的划分:
**6;
**5+1;
**4+2,4+1+1;
**3+3,3+2+1,3+1+1+1;
**2+2+2,2+2+1+1,2+1+1+1+1;
**1+1+1+1+1+1。
*/
/* ********************************************************************** */
/* ********************************************************************** */
/* 算法:
**记q(n,m)表示n的最大加数n1不大于m的划分个数,则有:
** |- 1 ,n=1,m=1
**q(n,m)=| q(n,n) ,n<m
** | 1+q(n,n-1),n=m ,n的划分由n1=n的划分和n1<=n-1的划分组成
** |_ q(n-m,m)+q(n,m-1),n>m>1,n的最大加数n1不大于m的划分由n1=m的划分和n1<=m-1的划分组成
*/
/* ***************************************************************** */
int int_partion( int n, int m)
{
if (n == 1 || m == 1 )
return 1 ;
else if (n < m)
return int_partion(n,n);
else if (n == m)
return 1 + int_partion(n,n - 1 );
else
return int_partion(n - m,m) + int_partion(n,m - 1 );
}
/* 非递归算法 */
#define N 6
int S[N + 1 ][N + 1 ];
int int_partion_2( int n, int m)
{
int i,j;
for (i = 1 ;i <= n;i ++ )
{
S[i][ 1 ] = 1 ;
S[ 1 ][i] = 1 ;
}
for (i = 2 ;i <= n;i ++ )
{
for (j = 2 ;j <= m;j ++ )
{
if (i == j)
S[i][j] = 1 + S[i][i - 1 ];
else if (i < j)
S[i][j] = S[i][i];
else
S[i][j] = S[i - j][j] + S[i][j - 1 ];
}
}
return S[n][m];
}
/* ***************************************************************** */
/* 集合划分问题:
**n个元素{1,2,,n}可以划分为多少个非空子集。该值实际上为Bell数,记为B(n)。
**例如:{1,2,3}的划分:
**{{1,2,3}}, {{1,2},{3}}, {{1,3},{2}}, {{1},{2,3}}
*/
/* ***************************************************************** */
/* ********************************************************************** */
/* 算法:
**记s(n,m)表示n个元素集合可以划分为m个非空子集的数量,该数实际上是Stirling数,则有:
**s(n,m)=m*s(n-1,m)+s(n-1,m-1); s(n,n+1)=0,s(n,0)=0,s(0,0)=1。
**显然:B(n)=s(n,1)+s(n+2)++s(n,n)
*/
/* ***************************************************************** */
// 计算stirling数
int stirling( int n, int m)
{
int min,i,j;
S[ 0 ][ 0 ] = 1 ;
for (i = 1 ;i <= n;i ++ )
S[i][ 0 ] = 0 ;
for (i = 0 ;i < n;i ++ )
S[i][i + 1 ] = 0 ;
for (i = 1 ;i <= n;i ++ )
{
if (i < m)
min = i;
else
min = m;
for (j = 1 ;j <= min;j ++ )
S[i][j] = j * S[i - 1 ][j] + S[i - 1 ][j - 1 ];
}
return S[n][m];
}
// 计算bell数
int bell( int n)
{
int num = 0 ;
stirling(n,n);
for ( int i = 1 ;i <= n;i ++ )
{
num += S[n][i];
}
return num;
}
int main()
{
int n = 4 ,m = 2 ;
// printf("%d pation numbers are:%d\n",n,int_partion_2(n,n));
printf( " %d,%d sirling number is:%d\n " ,n,m,stirling(n,m));
printf( " %d bell number is:%d\n " ,n,bell(n));
return 0 ;
}