打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
整数划分总结(动态规划)

先引入一个比较实际的问题:分苹果

题目

  1. M个相同苹果放到N个相同篮子里有多少种放法,允许有篮子不放。
  2. 1<=M<=10,1<=N<=10
  3. 例如5个苹果三个篮子,3,1,1 和 1,1,3是同一种放法
  4. 输入 7 3
  5. 输出 8

思路

设f(m,n) 为m个苹果,n个盘子的放法数目:

  1. 当n>m:必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即if(n>m) f(m,n) = f(m,m)  

  2. 当n<=m:不同的放法可以分成两类: 
    (1)有至少一个盘子空着,即相当于f(m,n) = f(m,n-1); 
    (2)所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n) = f(m-n,n).而总的放苹果的放法数目等于两者的和,即 f(m,n) =f(m,n-1)+f(m-n,n)

递归出口条件说明:

  1. 当n=1时,所有苹果都必须放在一个盘子里,所以返回1;
  2. 当没有苹果可放时,定义为1种放法;
  3. 递归的两条路,第一条n会逐渐减少,终会到达出口n==1;
  4. 第二条m会逐渐减少,因为n>m时,我们会return f(m,m) 所以终会到达出口m==0.

代码

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <stack>
  5. #include <algorithm>
  6. using namespace std;
  7. // apple 个 苹果 basket 个 篮子
  8. int ShareApple(int apple,int basket){
  9. // 因为我们总是让apple >= basket来求解的,所以apple - basket >= 0,
  10. // 让apple = 0时候结束,如果改为apple = 1,可能得不到正确解
  11. if(apple == 0 || basket == 1){
  12. return 1;
  13. }//if
  14. // 篮子多于苹果 按照苹果个数分
  15. else if(apple < basket){
  16. return ShareApple(apple,apple);
  17. }//else
  18. return ShareApple(apple,basket-1) + ShareApple(apple - basket,basket);
  19. }
  20. int main(){
  21. int apple,basket;
  22. //freopen("C:\\Users\\Administrator\\Desktop\\acm.txt","r",stdin);
  23. while(cin>>apple>>basket){
  24. cout<<ShareApple(apple,basket)<<endl;
  25. }//while
  26. return 0;
  27. }

是不是看着很简单?递归就是如此,思路很容易理解,但是很多子问题重复计算,复杂度很高。。。额。。。重点就是要说的动态规划咯(自底向上)

经典问题:整数划分

  1. /* 

  2.    整数划分 

  3.    (一)将n划分成若干不同整数之和的划分数 

  4.    (二)将n划分成若干正整数之和的划分数 

  5.    (三)将n划分成k个正整数之和的划分数 

  6.    (四)将n划分成最大数不超过k的划分数 

  7.    (五)将n划分成若干个 奇正整数之和的划分数 

  8. */  


  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cmath>
  5. #include<cstring>
  6. #include<vector>
  7. #include<queue>
  8. #include<set>
  9. #include<map>
  10. #include<algorithm>
  11. #include<sstream>
  12. #define eps 1e-9
  13. #define pi acos(-1)
  14. #define INF 0x7fffffff
  15. #define inf -INF
  16. #define MM 12900
  17. #define N 50
  18. using namespace std;
  19. typedef long long ll;
  20. const int _max = N + 10;
  21. int dp[_max][_max],n,k,out[6];
  22. int main(){
  23. #ifndef ONLINE_JUDGE
  24. freopen("input.txt","r",stdin);
  25. #endif // ONLINE_JUDGE
  26. while(scanf("%d%d",&n,&k)==2){
  27. /*****************整数划分(二)******************/
  28. memset(dp,0,sizeof(dp));
  29. dp[0][0] = 1;
  30. for(int i = 0; i <= n; ++ i)
  31. for(int j = 1; j <= n; ++ j){
  32. if(j>i)dp[i][j]=dp[i][i];
  33. else dp[i][j] = dp[i-j][j] + dp[i][j-1];
  34. }
  35. out[1] = dp[n][n];
  36. /*****************整数划分(四)******************/
  37. out[3] = dp[n][k];
  38. /*****************整数划分(三)******************/
  39. memset(dp,0,sizeof(dp));
  40. dp[0][0] = 1;
  41. for(int i = 1; i <= N; ++ i)
  42. for(int j = 1; j <= i; ++ j){
  43. dp[i][j] = dp[i-1][j-1]+dp[i-j][j];
  44. }
  45. out[2] = dp[n][k];
  46. /*****************整数划分(五)******************/
  47. memset(dp,0,sizeof(dp));
  48. dp[0][0] = 1;
  49. for(int i = 0; i <= n; ++ i)
  50. for(int j = 1; j <= n; ++ j){
  51. if(j&1){
  52. if(j>i)dp[i][j] = dp[i][i];
  53. else dp[i][j] = dp[i-j][j]+dp[i][j-1];
  54. }
  55. else dp[i][j] = dp[i][j-1];
  56. }
  57. out[4] = dp[n][n];
  58. /*****************整数划分(一)******************/
  59. memset(dp,0,sizeof(dp));
  60. dp[0][0] = 1;
  61. for(int i = 0; i <= n; ++ i)
  62. for(int j = 1; j <= n; ++ j){
  63. if(j>i)dp[i][j]=dp[i][i];
  64. else dp[i][j] = dp[i-j][j-1] + dp[i][j-1];
  65. }
  66. out[5] = dp[n][n];
  67. /*****************输出******************/
  68. for(int i = 1; i<= 5; ++ i)
  69. printf("%d\n",out[i]);
  70. printf("\n");
  71. }
  72. return 0;
  73. }
  74. /*
  75. /*****(一)将n划分成若干不同整数之和的划分数************
  76. dp[i][j]表示将整数i划分成不超过j的划分数,分含不含j两种情况
  77. dp[0][0] = 1
  78. dp[i][j] = dp[i-j][j-1] + dp[i][j-1];(j<=i)
  79. = dp[i][i] (j >i)
  80. =>ans = dp[n][n]
  81. /*****(二)将n划分成若干正整数之和的划分数*************
  82. dp[i][j]表示将整数i划分成不超过j的划分数,分含不含j两种情况
  83. 与(一)区别,j可重复
  84. dp[0][0] = 1
  85. dp[i][j] = dp[i-j][j] + dp[i][j-1];(j<=i)
  86. = dp[i][i] (j >i)
  87. =>ans = dp[n][n]
  88. /*****(三)将n划分成k个正整数之和的划分数*************
  89. dp[i][j]表示将整数i划分成j个正整数的划分数,考虑j组数中含不含1
  90. dp[0][0] = 1
  91. dp[i][j] = dp[i-1][j-1] + dp[i-j][j];
  92. 如果不包含1,那么每组数至少为2,从每堆数中各拿出1还能够成j堆数dp[i-j][j]
  93. =>ans = dp[n][k]
  94. /*****(四)将n划分成最大数不超过k的划分数************
  95. dp[i][j]表示将整数i划分成不超过j的划分数,分含不含j两种情况
  96. 是(二)的特例
  97. dp[0][0] = 1
  98. dp[i][j] = dp[i-j][j] + dp[i][j-1];(j<=i)
  99. = dp[i][i] (j >i)
  100. =>ans = dp[n][k]
  101. /*****(五)将n划分成若干个 奇正整数之和的划分数******
  102. dp[i][j]表示将整数i划分成不超过j的划分数,分含不含j两种情况
  103. dp[0][0] = 1;
  104. j是奇数,正常判断
  105. dp[i][j] = dp[i-j][j] + dp[i][j-1];(j<=i)
  106. = dp[i][i] (j >i)
  107. j是偶数,dp[i][j] = dp[i][j-1]//往下递推
  108. =>ans = dp[n][n]
  109. */
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
548,动态规划解最长的斐波那契子序列的长度
动态规划(DP)
深入理解动态规划算法 - 凑整数
常用的十种算法
干货|十分钟教你用动态规划算法解Travelling Salesman Problem(TSP)问题...
剑指 Offer 14- I. 剪绳子
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服