转自:https://yq.aliyun.com/articles/445250
总时间限制: 100ms 内存限制: 65536kB
描述
将正整数n 表示成一系列正整数之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 ,k>=1 。
正整数n 的这种表示称为正整数n 的划分。正整数n 的不同的划分个数称为正整数n 的划分数。
输入
标准的输入包含若干组测试数据。每组测试数据是一个整数N(0 < N <= 50)。
输出
对于每组测试数据,输出N的划分数。
样例输入
5
样例输出
7
提示
5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1
递推表达式如下:
f(n, m) =1; (n=1 or m=1)
=f(n, n); (n<m)
=1+ f(n, m-1); (n=m)
=f(n-m,m)+f(n,m-1); (n>m)
我们定义 dp[n][k] 表示将n进行划分,最大的数不超过k的方案有多少种。关键是这个,
在递归中我们顶一顶是 f(n,k) ,而在动态规划中我们定义的是 dp[n][k]。然后将代码,照着递归写就差不多了,,
那么我们可以得到如下的递推方案:
dp[n][k] = dp[n][k-1] + dp[n-k][k];
很显然其中的dp[n][k-1]便是将n进行进行整数的划分,最大的数不超过k-1的方案数;dp[n-k][k]表示拿出一个k后,剩下的数被不超过k的数的表示的方案数。
其中当k>n的时候,则和dp[n][n]的值相同,下面通过递推的方式求出所有的解,然后对应的输入n,输出dp[n][n]就行了。
1 #include<iostream>
2 #include<cstring>
3 #include<cstdlib>
4 #include<cstdio>
5 using namespace std;
6
7 const int MAX = 100;
8 int dp[MAX][MAX];//二维数组,对MAX进行划分,最大的数不超过MAX的方案数
9
10 void Dynamic()
11 {
12 for(int i=1; i<MAX; i++)
13 {
14 dp[i][1] = dp[1][i] = dp[0][i] = 1;//当n或m==1时,dp[][]=1,
//即方案数为1个,当n=0时,也为1,而当m=0时,则不为1
15 }
16 for(int i=2; i<MAX; i++)
17 {
18 for(int j=2; j<MAX; j++)
19 {
20 if(j<=i) dp[i][j] = dp[i][j-1] + dp[i-j][j];
//如果m<n,即n>m 递推方程 f(n,m)=f(n-m,m)+f(n,m-1);
//为啥这里 将m==n的情况也包含进去了,原因是 dp[i-j=0][]=1,
//和原表达式 f(n,m)=f(n,m-1)+1 结果一样,。。
21 else dp[i][j] = dp[i][i];
// 如果 n<m f(n,m)=f(n,n)
22 }
23 }
24 }
25 int main()
26 {
27 int n;
28 Dynamic();
29 while(scanf("%d",&n)!=EOF)
30 {
31 printf("%d\n",dp[n][n]);
32 }
33 return 0;
34 }