整数划分问题---动态规划、递归

265 篇文章 1 订阅

转自 http://blog.csdn.net/xiaozhuaixifu/article/details/9796725

第一:

将一个整数 n 划分为 不超过m 组 的划分数 如 
n=4
m=3
输出:
4 { 1+1+2=1+3=2+2=4}
思路:使用动态规划: 定义状态:  dp[i][j] j的i划分的组数
递推:dp[i][j]=dp[i][j-i]+dp[i-1][j] ------当m=n时,变成了常见的整数划分问题
[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<cstring>  
  3. using namespace std;  
  4. const int maxn=1000+10;  
  5. int dp[maxn][maxn],n,m;  
  6. void sovle(){  
  7.     dp[0][0]=1;  
  8.     for(int i=1;i<=m;i++){  
  9.         for(int j=0;j<=n;j++){  
  10.             if(j-i>=0){  
  11.                 dp[i][j]=dp[i][j-i]+dp[i-1][j];  
  12.             }  
  13.             else dp[i][j]=dp[i-1][j];  
  14.         }  
  15.     }  
  16.       
  17. }  
  18. int main()  
  19. {  
  20.     memset(dp,0,sizeof(dp));  
  21.     n=4;m=4;  
  22.     sovle();   
  23.     cout<<dp[m][n]<<endl;  
  24. }  

第二:

我们用递归+记忆化的方法来解决普通整数划分问题:定义 f(n,m)为将整数n划分为一系列整数之和,其中加数
最大不超过m。
得到下面的递推关系式:
 当n==1 || m==1 只有一种划分,即 1 或者 1+1+1......+1
当m>n 显然,等价于 f(n,n)
当m==n 此时:我考虑加数包含m与否的两种情况:
1)划分不包含m,即f(n,m-1)---所有m-1的划分
2)划分包含 m,此时只有一种即 m
所以当m==n时,有 f(n,m)=f(n,m-1)+1
当m<n时,
1)包含m时,{m,x1,x2,x3....xi}此时 等价于 f(n-m,m)
2)不包含m时,显然f(n,m-1)
所以f(n,m)=f(n,m-1)+f(n-m,m)
采用记忆化技术优化复杂度:
[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<cstring>  
  3. using namespace std;  
  4. const int maxn=1000+10;  
  5. int f[maxn][maxn];  
  6. int  getspilit(int n,int m)  
  7. {  
  8.     if(n==1||m==1)return 1;  
  9.     if(m>n){  
  10.         if(f[n][m]!=-1)return f[n][m];  
  11.         return f[n][m]=getspilit(n,n);  
  12.     }  
  13.     if(n==m){  
  14.         if(f[n][m]!=-1)return f[n][m];  
  15.         return f[n][m]=getspilit(n,m-1)+1;  
  16.     }   
  17.     return f[n][m]=(getspilit(n-m,m)+getspilit(n,m-1));  
  18. }  
  19. int main()  
  20. {  
  21.     int n=4,m=4;  
  22.     memset(f,-1,sizeof(f));  
  23.     cout<<getspilit(n,m)<<endl;  
  24.     return 0;  
  25. }  

第三:

将整数n划分为一系列连续的整数之和即:
15=7+8
    =4+5+6
    =1+2+3+4
这里我们假设划分之后最小的整数位x ,那么 x+(x+1)+(x+2)......+(x+m)假设一共有i个整数,整理得:
x*i+i*(i-1)/2=n
i=1,2,3.....其中i的限制条件为:s1=i*(i-1)/2<=n,只有当x为整数时才有可能。
[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<cstring>  
  3. using namespace std;  
  4. int getsplit(int n)  
  5. {  
  6.     int i,s1,s2,x,sum=0;  
  7.     for(i=1;(s1=i*(i-1)/2)<=n;i++)  
  8.     {  
  9.         s2=n-s1;  
  10.         x=s2/i;  
  11.         if(x==0)break;  
  12.         if(s2%i==0)  
  13.         {  
  14.             cout<<x<<" ";  
  15.             for(int j=1;j<i;j++)cout<<x+j<<" ";  
  16.             cout<<endl;  
  17.             sum++;  
  18.         }  
  19.     }  
  20.     return sum;  
  21. }  
  22. int main()  
  23. {  
  24.     int n=15;  
  25.     cout<<getsplit(n)-1<<" methods to split the number."<<endl;  
  26. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值