算法学习->整数拆分问题

动态规划典型题目/

00 题目

将正整数n无需拆分为最大数为k的拆分方案有多少种?

要求所有的拆分方案不重复。

示例:

输入:n=5,k=5

输出:(5,5)=7

示例分析:

  1. 5=5

  2. 5=4+1

  3. 5=3+2

  4. 5=3+1+1

  5. 5=2+2+1

  6. 5=2+1+1+1

  7. 5=1+1+1+1+1

所以一共七种。

01 思路

01-1 类型

求解这一问题的思路有很多,在这里是想作为动态规划的例题进行分析。所以采用动态规划。

01-2 算法

使用动态规划,最重要的是状态转移方程

简单说就是当前状态对下一状态,依据限制条件,进行决策的函数。

来想一下,n和k的关系:

  • n=1或者k=1时,显然 f(n,k)=1;

  • n<k时,有 f(n,k)=f(n,n);

  • n=k时,f(n,n)=f(n,n-1)+1

    • //即将k降一次的感觉,因为这种情况必有一种拆分是他自己,比如上面的5,5

  • n>k时,我们考虑一下,会有两种大的情况:

    • 第一种,n的拆分里有k,那这一大类其实相当于f(n,k)=f(n-k,k)

    • 第二种,n的拆分里没k,那就是拆分里所有数都比k小,即n的(k-1)的拆分,即f(n,k)=f(n,k-1);

02 代码

这样的代码就很好实现。

典型动态规划实现的话,就只有嵌套循环和if-else循环。

 1 //求解n的k拆分
 2 #include<stdio.h>
 3 #include<string.h>
 4 #define MAXN 500
 5 int dp[MAXN][MAXN];
 6 void Split(int n, int k){
 7     for(int i = 1; i <= n; i++){
 8         for(int j = 1; j <= k; j++){
 9             if(i == 1 || j == 1){
10                 dp[i][j] = 1;
11             }
12             else if(i < j){
13                 dp[i][j] = dp[i][i];
14             }
15             else if(i == j){
16                 dp[i][j] = dp[i][j-1]+1;
17             }
18             else{
19                 dp[i][j] = dp[i][j-1] + dp[i-j][j];
20             }
21         }
22     }
23 }
24 int main(){
25         int n=5,k=5;
26         memset(dp, 0, sizeof(dp));
27         Split(n,k);
28         printf("(%d, %d)=%d",n,k,dp[n][k]);
29         return 0;
30 }
31  

 

因为这个问题是递归的,所以可以采用递归来写,解决过程是自顶向下的。当然就在递归过程中将算过的子问题放进dp数组,在后续dp不等0时就是此前已经算过了,直接return就行。

这种方法也叫备忘录法

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define MAXN 500
 4 int dp[MAXN][MAXN];
 5 int dpf(int n, int k){
 6     if(dp[n][k] != 0)return dp[n][k];
 7     if(n == 1 || k == 1){
 8         dp[n][k] = 1;
 9         return dp[n][k];
10     }
11     else if(n < k){
12         dp[n][k] = dpf(n, n);
13         return dp[n][k];
14     }
15     else if(n == k){
16         dp[n][k] = dpf(n, k-1)+1;
17         return dp[n][k];
18     }
19     else{
20         dp[n][k] = dpf(n, k-1)+dpf(n-k, k);
21         return dp[n][k];
22     }
23 }
24 int main(){
25     int n=5,k=5;
26     memset(dp, 0, sizeof(dp));
27     printf("(%d, %d)=%d",n,k,dpf(n,k));
28     return 0;
29 }

 

 

posted @ 2021-11-03 12:51  climerecho  阅读(317)  评论(0编辑  收藏  举报