NYOJ_571_整数划分(三)

/*
第一行:将n划分成若干正整数之和的划分数。
状态转移方程:dp[i][j]:和为i、最大数不超过j的拆分数
dp[i][j]可以分为两种情况:1、拆分项至少有一个j 2、拆分项一个j也没有
dp[i][j]=dp[i-j][[j]+dp[i][j-1]

第二行:将n划分成k个正整数之和的划分数。
dp[n-k][k]:相当于把k个1从n中拿出来,然后和n-k的拆分项相加的个数

第三行:将n划分成若干最大不超过k的正整数之和的划分数。
dp[n][k]

第四行:将n划分成若干奇正整数之和的划分数。
dp1[i][j]是当前的划分数为i,最大值为j时的中的划分数,则状态转移方程为
dp1[i][j]=dp1[i][i]if(j>i&&j%2==1)
=dp1[i][i-1]if(j>i&&j%2==0)(最大数不可能为偶数)
=dp1[i-j][j]+dp1[i][j-2]没用到j时划分不变,即dp1[i][j-2],用到则是dp1[i-j][j];

第五行:将n划分成若干完全不同正整数之和的划分数。
dp2[i][j]可以分两种情况:1、dp1[i][j-1]为不选择j时的方案  2、dp1[i-j][j-1]为选择j时的方案
0-1背包:dp2[i][j]=dp2[i][j-1]+dp2[i-j][j-1]

第六行:将n划分成不超过k个正整数之和的划分数。
dp[n][k]: ferrers共轭图像
比如 24=5+5+5+4+3+2,6个数,最大数为5
     24=6+6+5+4+3 5个数,最大数为6
*/
#include <stdio.h>
#define N 52
int dp[N][N] = {0} , dp1[N][N] = {0}  , dp2[N][N] = {0} ;
void  Divid(){
      dp[0][0] = 1 ;
      for( int i = 0 ; i < N ; i++ )
            for( int j = 1 ; j < N ; j++ ){
                  if( i < j ) //当i<j时 只能j分到i而已,所以情况有1种
                        dp[i][j] = dp[i][i] ;
                  else
                        dp[i][j] = dp[i-j][j] + dp[i][j-1] ;
            }
}
void Divid1(){
      for( int i = 1 ; i < N ; i++ )
            dp1[i][1] = 1 ;           //最大值为1时只能有本身组成,Answer为1
      for( int i = 1 ; i < N ; i+=2 )
            dp1[0][i] = 1 ;
      dp1[0][0] = 1 ;
      for( int i = 1 ; i < N ; i++ )
            for( int j = 3 ; j < N ; j+=2 ){ //j是永远的奇数
                  if( j > i ){
                        if( i&1 )
                              dp1[i][j] = dp1[i][i] ;
                        else
                              dp1[i][j] = dp1[i][i-1] ;
                  }
                  else
                        dp1[i][j] = dp1[i-j][j] + dp1[i][j-2] ;
            }
}
void Divid2(){
      for( int i = 1 ; i < N ; i++ ){
            dp2[0][i] = 1 ;
            dp2[1][i] = 1 ;
      }
      for( int i = 2 ;i < N ; i++ )
            for( int j = 1 ;j < N ; j++ ){
                  if( j > i )
                        dp2[i][j] = dp2[i][i] ;
                  else
                        dp2[i][j] = dp2[i-j][j-1] +dp2[i][j-1] ;
            }
}
int main(){
      int n , k ;
      Divid() ;
      Divid1() ;
      Divid2() ;
      while( ~scanf( "%d%d" , &n , &k ) )
      {
            printf( "%d\n" , dp[n][n] ) ;
            printf( "%d\n" , dp[n-k][k] ) ;
            printf( "%d\n" , dp[n][k]) ;
            printf( "%d\n" , n&1 ? dp1[n][n] : dp1[n][n-1] ) ;
            printf( "%d\n\n" , dp2[n][n]) ;
      }
      return 0;
}

 

posted @ 2013-05-04 15:49  小仪在努力~  阅读(227)  评论(0)    收藏  举报