整数划分问题是一个经典的递归问题。
dp[n][m]表示 整数n的m划分为 n=x1+x2+x3+...+x;其中xi的最大值小于等于m;
那么我们讨论一下怎么把问题转换为其子问题;
1、当m=1或者n=1 时 显然dp[n][m]=1;
2、当n<m时 问题转换为整数n的n划分 dp[n][m]=dp[n][n];
3、当n=m时 分两种情况考虑
3.1、当划分的数中包含m时,dp[n][m]=1;
3.2、当划分的数不包含m时,问题转换为整数n的m-1的划分 dp[n][m]=dp[n][m-1];
4、当n>m时 同样分为两种情况
4.1、当划分的数中包含m时,问题转换为整数n-m的m的划分 dp[n][m]=dp[n-m][m];
4.2、当划分的数中不包含m时,问题转换为整数n的m-1的划分 dp[n][m]]=dp[n][m-1];
综上所述:
dp(n, m)= 1; (n=1 或者 m=1)
dp(n, n); (n<m)
1+dp(n, m-1); (n=m)
dp(n-m,m)+dp(n,m-1); (n>m)
直接递归会超时,那么我们可以采用记忆化搜索的方式解决或者用递推。
下面是记忆化搜索的代码:
#include <stdio.h> #include <string.h> #define maxn 125 int dp[maxn][maxn]; int dfs(int n,int m) { int i,j; if(dp[n][m]!=-1) return dp[n][m]; if(n==1 || m==1) return 1; if(n<m) dp[n][m]=dfs(n,n); else if(n==m) dp[n][m]=1+dfs(n,m-1); else if(n>m) dp[n][m]=dfs(n-m,m)+dfs(n,m-1); return dp[n][m]; } int main() { int N,sum; memset(dp,-1,sizeof(dp)); while(scanf("%d",&N)==1) { sum=dfs(N,N); printf("%d\n",sum); } }