划分问题

#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 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值