整數劃分問題---動態規劃、遞迴
阿新 • • 發佈:2019-01-06
第一:
將一個整數 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時,變成了常見的整數劃分問題#include<iostream> #include<cstring> using namespace std; const int maxn=1000+10; int dp[maxn][maxn],n,m; void sovle(){ dp[0][0]=1; for(int i=1;i<=m;i++){ for(int j=0;j<=n;j++){ if(j-i>=0){ dp[i][j]=dp[i][j-i]+dp[i-1][j]; } else dp[i][j]=dp[i-1][j]; } } } int main() { memset(dp,0,sizeof(dp)); n=4;m=4; sovle(); cout<<dp[m][n]<<endl; }
第二:
我們用遞迴+記憶化的方法來解決普通整數劃分問題:定義 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)#include<iostream> #include<cstring> using namespace std; const int maxn=1000+10; int f[maxn][maxn]; int getspilit(int n,int m) { if(n==1||m==1)return 1; if(m>n){ if(f[n][m]!=-1)return f[n][m]; return f[n][m]=getspilit(n,n); } if(n==m){ if(f[n][m]!=-1)return f[n][m]; return f[n][m]=getspilit(n,m-1)+1; } return f[n][m]=(getspilit(n-m,m)+getspilit(n,m-1)); } int main() { int n=4,m=4; memset(f,-1,sizeof(f)); cout<<getspilit(n,m)<<endl; return 0; }
第三:
將整數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為整數時才有可能。#include<iostream>
#include<cstring>
using namespace std;
int getsplit(int n)
{
int i,s1,s2,x,sum=0;
for(i=1;(s1=i*(i-1)/2)<=n;i++)
{
s2=n-s1;
x=s2/i;
if(x==0)break;
if(s2%i==0)
{
cout<<x<<" ";
for(int j=1;j<i;j++)cout<<x+j<<" ";
cout<<endl;
sum++;
}
}
return sum;
}
int main()
{
int n=15;
cout<<getsplit(n)-1<<" methods to split the number."<<endl;
}