整数划分 用递归,动态规划,母函数法实现

1.      整数划分类

输入:

 

每组输入是两个整数n和k。(1 <= n <= 50, 1<= k <= n)

 

输出:

 

对于每组输入,请输出六行。

 

第一行: 将n划分成若干正整数之和的划分数。

第二行: 将n划分成k个正整数之和的划分数。

第三行: 将n划分成最大数不超过k的划分数。

第四行: 将n划分成若干奇正整数之和的划分数。

第五行: 将n划分成若干不同整数之和的划分数。

第六行: 打印一个空行。

 

该题采用了三种方法实现,分别是采用递归法,母函数法,以及动态规划的方法规划。

递归法思想:

1.将n划分成不大于m的划分法: 

   1).若是划分多个整数可以存在相同的:

    dp[n][m]= dp[n][m-1]+ dp[n-m][m]  dp[n][m]表示整数 n 的划分中,每个数不大于 m 的划分数。
       则划分数可以分为两种情况:
       a.划分中每个数都小于 m,相当于每个数不大于 m- 1, 故划分数为 dp[n][m-1].
       b.划分中有一个数为 m. 那就在 n中减去 m ,剩下的就相当于把 n-m 进行划分, 故划分数为 dp[n-m][m];

  2).若是划分多个不同的整数:

  dp[n][m]= dp[n][m-1]+dp[n-m][m-1]   dp[n][m]表示整数 n 的划分中,每个数不大于 m 的划分数。
      同样划分情况分为两种情况:
      a.划分中每个数都小于m,相当于每个数不大于 m-1,划分数为 dp[n][m-1].
      b.划分中有一个数为 m.在n中减去m,剩下相当对n-m进行划分,

   并且每一个数不大于m-1,故划分数为 dp[n-m][m-1]

 2.将n划分成k个数的划分法:

 dp[n][k]=dp[n-k][k]+ dp[n-1][k-1];

     方法可以分为两类:
       第一类: n 份中不包含 1 的分法,为保证每份都 >= 2,可以先拿出 k 个 1 分
     到每一份,然后再把剩下的 n- k 分成 k 份即可,分法有: dp[n-k][k]
       第二类: n 份中至少有一份为 1 的分法,可以先那出一个 1 作为单独的1份,剩
     下的 n- 1 再分成 k- 1 份即可,分法有:dp[n-1][k-1]

  

 3.将n划分成若干奇数的划分法:

    g[i][j]:将i划分为j个偶数

    f[i][j]:将i划分为j个奇数
     g[i][j] = f[i - j][j];
     f[i][j] = f[i- 1][j - 1] + g[i - j][j];

 

主界面:

 

输入1:递归法实现

输入2: 母函数法实现

DP法:输入3时没有结果输出:

由于时间暂时不够,动态规划法暂时没有实现,本质原理在于采用递归式自底向上的通过查表的方法,所以避免了向递归那样的重复计算,从而明显的降低了时间。

 

输入0:按任意键退出

算法思路:

附件:

#include<stdio.h>

#include<string.h>

#include<windows.h>

//母函数法函数声明

void Polynominal(int n) ;

int TotalDivision(int n);

int LesskDivision(int n,int m);

int OddDivision(int n);

int DifferDivision(int n);

 

//递归法函数声明

int IntDivRecursive(int n,int k);

int TotalDivRecursive(int n) ;

int DifferDivRecursive(int n,int k) ;

int NumKDivision(int n,int k) ;

int menu_select() ;

 

void initRecursive();

void initGenerFunc() ;

 

#define MAX 100

int a[MAX],b[MAX],c[MAX];    //a[],b[]数组表示多项式系数的相乘,c[]暂存相乘的运算结果

void Polynominal(int n)          //多项式函数的计算

{

         inti,j;

         //intk=1;

        

         for(i=0;i<=n;i++)

         {

                    //k++;

                    for(j=0; i+j<=n;j++)   //i+j<=n表示当x^n中n次数超过它时已没有意义。这里j=j+k表示2..n的数出现次数的表示,这样是错误的。

                             c[i+j]=a[i]*b[j]+c[i+j];

         }

        

 

}

 

int TotalDivision(int n)

{

         inti,j;

         memset(c,0,sizeof(int)*(n+1));  //只需存放到系数an为止,超过的系数无需存放,那些数据无意义。

         for(i=0;i<=n;i++)

                   a[i]=1;

         intk=1;

         do{

           k++;

           memset(b,0,sizeof(int)*(n+1));  //其他不可能出现的项系数为0

           for(j=0;j<=n;j=j+k)           //由于多项式的的次数不是连续的

           {

                   b[j]=1;

           }

 

           Polynominal(n);

           memcpy(a,c,sizeof(int)*(n+1));

           memset(c,0,sizeof(int)*(n+1));

          

          

         }while(n>=k);

         returna[n];

 

 

}

 

/*

int NumKDivision(int n,int m)

{

         inti,j;

         intcount=0;

         memset(c,0,sizeof(int)*(n+1));  //只需存放到系数an为止,超过的系数无需存放,那些数据无意义。

         for(i=0;i<=m;i++)

         {

                   a[i]=1;

//               count[i]=i;

         }

         intk=1;

         do{

           k++;

           memset(b,0,sizeof(int)*(n+1));  //其他不可能出现的项系数为0

           for(j=0;j<=n;j=j+k)           //由于多项式的的次数不是连续的

           {

                   b[j]=1;

         //      count[j]=j/k;

           }

 

           Polynominal(n);

           memcpy(a,c,sizeof(int)*(n+1));

           memset(c,0,sizeof(int)*(n+1));

          

          

         }while(n>=k);

         returna[n];

 

 

}

*/

 

int LesskDivision(int n,int m)

{

         inti,j;

         memset(c,0,sizeof(int)*(n+1));  //只需存放到系数an为止,超过的系数无需存放,那些数据无意义。

         for(i=0;i<=n;i++)

                   a[i]=1;

         intk=1;

         while(m>k){                 //只需改这句一话,m>=k是错误的

           k++;

           memset(b,0,sizeof(int)*(n+1));  //其他不可能出现的项系数为0

           for(j=0;j<=n;j=j+k)           //由于多项式的的次数不是连续的

           {

                   b[j]=1;

           }

 

           Polynominal(n);

           memcpy(a,c,sizeof(int)*(n+1));

           memset(c,0,sizeof(int)*(n+1));  

          

         }

         returna[n];

 

 

}

 

 

 

int OddDivision(int n)

{

         inti,j;

         memset(c,0,sizeof(int)*(n+1));  //只需存放到系数an为止,超过的系数无需存放,那些数据无意义。

         for(i=0;i<=n;i++)

                   a[i]=1;

         intk=1;

         do{

           k+=2;

           memset(b,0,sizeof(int)*(n+1));  //其他不可能出现的项系数为0

           for(j=0;j<=n;j=j+k)           //由于多项式的的次数不是连续的

           {

                   b[j]=1;

           }

 

           Polynominal(n);

           memcpy(a,c,sizeof(int)*(n+1));

           memset(c,0,sizeof(int)*(n+1));

          

          

         }while(n>=k);

         returna[n];

 

}

 

int DifferDivision(int n)

{

         inti,j;

         memset(c,0,sizeof(int)*(n+1));  //只需存放到系数an为止,超过的系数无需存放,那些数据无意义。

//      for(i=0;i<=n;i++)

         memset(a,0,sizeof(int)*(n+1));   //这里和上面两个函数不同,前面初始化已经全部置为1了,所以输出错误结果在于此。

         a[1]=1;

    a[0]=1;

         intk=1;

         do{

           k++;

           memset(b,0,sizeof(int)*(n+1));  //其他不可能出现的项系数为0

           b[0]=1;

           b[k]=1;

          

           Polynominal(n);

           memcpy(a,c,sizeof(int)*(n+1));

           memset(c,0,sizeof(int)*(n+1));

          

          

         }while(n>=k);

         returna[n];

 

}

 

 

 

 

 

//递归法实现整数划分

#include<stdio.h>

int IntDivRecursive(int n,int k)  //将n划分成最大数不超过k的划分数

{

         if(n==1|| k==1)

                   return1;

         elseif(n==k)

                   returnIntDivRecursive(n,n-1)+1;

         elseif(n<k)

                   returnIntDivRecursive(n,n);

         elseif(n>k)

                   returnIntDivRecursive(n-k,k)+IntDivRecursive(n,k-1);

}

 

int TotalDivRecursive(int n)         //将n划分成若干正整数之和的划分数

{

         inttotal=IntDivRecursive(n,n);

         returntotal;

}

 

int DifferDivRecursive(int n,int k)  //将n划分成若干不同整数之和的划分数。

{

 

         if(n==1)      

                   return1;

//      if(n==0)        //表示前一次递归时,n==k,即此时该元素就当做一个划分

//               return1;

         if(n==k)

                   return  DifferDivRecursive(n,k-1)+1;  //这句话和上面一句if(n==0)其实等价

         if(k==1)

                   return0; //注:此时k=1的解要省去,因为所以这个解都是有{1...1}组成

 

 

   else //if(n>k)

                   return  DifferDivRecursive(n-k,k-1)+DifferDivRecursive(n,k-1);

        

}

 

int NumKDivision(int n,int k)         //将n划分成k个正整数之和的划分数。

{

         if(k==1)

                   return1;

         elseif(n>k)

                   returnNumKDivision(n-1,k-1)+NumKDivision(n-k,k);

         elseif(n==k)

                   return1;

         elseif(n<k)

                   return0;                //该函数关键在于这一步,当n<k时,(没有意义),无需再进行递归。

}

 

//int OddDivision(int n,int )

/*

int OddDivision((int n,int m)    //采用背包问题的解法

{

  int a[][]

  for(inti=0;i<=n;i++)

    for(intj=0;j<=n;j++)

    {

        if(i<1||j<1)a[i][j]=0;

        elseif(i==1||j==1)a[i][j]=1;

        elseif(i<j)a[i][j]=a[i][i];

        elseif(i==j&&i%2==1)a[i][j]=a[i][j-1]+1;

        elseif(i==j&&j%2==0)a[i][j]=a[i][j-1];

        elsea[i][j]=a[i][j-2]+a[i-j][j];

    }

  return a[i][j];

}

*/

 

 

int menu_select()   /*菜单函数*/

{

  char c;

 

 //system("cls");/*运行前清屏*/

 printf("\t\t**** 魔方 Author byYongLiu ****\n"); /*菜单选择*/

 printf("\t\t  1. 递归法实现 |\n");

 printf("\t\t  2. 母函数法实现|\n");

 printf("\t\t  3. 动态规划法实现|\n");

 printf("\t\t  0. 退出 |\n");

 printf("\t\t*****************************************\n");

 printf("\t\t\t请选择(0-3):");

 

  do{

     c=getchar(); /*读入选择*/

  }while(c<'0'||c>'3');

  return(c-'0'); /*返回选择*/

}

 

int main() /*主函数*/

{

 

 

  for(;;)

         {

      switch(menu_select())/*选择判断*/

                   {

          case 1:

          printf("\t\t1. 递归法实现 |\n");

          initRecursive();

          break;

 

     

          case 2:

          printf("\t\t2. 母函数法实现|\n");

          initGenerFunc();

          break;

 

    

         case 3:

          printf("\t\t3. 动态规划法实现|\n");

 

          printf("\t\t\t");

          break;

 

 

          case 0:

          printf("\t\t\t结束退出!\n"); /*结束程序*/

          printf("\t\t\t");

          system("pause");

          exit(0);

                   }       

         }

  return 1;

}

 

 

 

void initRecursive()

{

 

         intn,k;

         printf("\t\tinputtwo number n k :");

         scanf("%d%d",&n,&k);

 

         printf("\t\t将n划分成若干正整数之和的划分数 %d\n",TotalDivRecursive(n));        将n划分成若干正整数之和的划分数

         printf("\t\t将n划分成k个正整数之和的划分数 %d\n",NumKDivision(n,k));       将n划分成k个正整数之和的划分数

         printf("\t\t将n划分成最大数不超过k的划分数 %d\n",IntDivRecursive(n,k));    将n划分成最大数不超过k的划分数

//      printf("\t\t将n划分成若干奇正整数之和的划分数 %d\n", OddDivision(n,n));       将n划分成若干奇正整数之和的划分数。

         printf("\t\t将n划分成若干不同整数之和的划分数 %d\n", DifferDivRecursive(n,n));    将n划分成若干不同整数之和的划分数

         printf("\n");

         printf("\n");

}  

 

void initGenerFunc()                      

{

         intn,k;

         printf("\t\tinputtwo number n k :");

         scanf("%d%d",&n,&k);

//      Initiation(n);

         printf("\t\t将n划分成若干正整数之和的划分数 %d\n",TotalDivision(n));   //总划分

  //printf("\t\t%d\n",NumKDivision(n));    //k个数组成的划分 ,用母函数暂时不知道怎么实现

         printf("\t\t将n划分成最大数不超过k的划分数 %d\n",LesskDivision(n,k));   //不超过k

    printf("\t\t将n划分成若干奇正整数之和的划分数 %d\n",OddDivision(n));     //奇数组成的划分

    printf("\t\t将n划分成若干不同整数之和的划分数 %d\n",DifferDivision(n));  //不同数的划分

         printf("\n");

         printf("\n");

 

}

 注:代码上传在http://download.csdn.net/detail/liuyongvs2009/7077279

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值