简单整数划分——动态规划

转自: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;//当nm==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 }
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页