当前位置:   article > 正文

【动态规划】基础DP--硬币组合_动态规划 硬币

动态规划 硬币

动态规划(Dynamic Programming,DP)一般是多阶段决策问题,把一个复杂问题分解为相对简单的子问题,再一一解决,得到原复杂问题的最优解。

求解DP问题的步骤:定义状态、状态转移、算法实现。

DP问题可以分为线性和非线性的。

线性DP。线性DP有两种方法:顺推与逆推。在线性DP中,常常用“表格”来处理状态,用表格这种图形化工具可以清晰易懂地演示推导过程。

非线性DP。例如:树形DP,建立在树上,也有两个方向:1)根->叶,根传递有用的信息给子节点,最后根得出最优解。2)叶->根,根的子节点传递有用的信息给根,最后根得出最优解。

最少硬币问题

有n种硬币,面值为v1,v2,...,vn,数量无限。输入非负整数s,选用硬币,使其和为s。要求输出最少的硬币组合。

解决:定义一个数组 int Min[MONEY],其中Min[i]是金额j对应的最少硬币数量。

初始值Min[0](即总金额为0时)需要0个硬币

金额为1时,Min[1]=Min[0]+1=Min[1-1]+1;

金额为2时,Min[2]=Min[1]+1=Min[2-1]+1;.......

金额为5时,Min[5]=Min[5-5]+1;// 有五元的面值,总金额减5,加1个(五元)硬币

金额为6时,Min[6]=Min[6-5]+1;..........

递推式:Min[i]=min(Min[i],Min[i-type[j]]+1;

(为什么是Min[i]?因为一开始总金额先(取)减type[0]的面额,得到Min[i];然后再(取)减type[1]面额,以此类推,比较之后,才取最少硬币数量)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MONEY = 251;//定义最大金额
  4. const int VALUE = 5;//5种硬币
  5. int type[VALUE] = { 1,5,10,50,100 };//5种面值
  6. int Min[MONEY];//每个金额对应最少的硬币数量
  7. void minCoin() {
  8. for (int i = 0; i < MONEY; i++) {
  9. Min[i] = INT_MAX;//初始值为无穷大
  10. }
  11. Min[0] = 0;
  12. for (int i = 0; i < VALUE; i++) {
  13. for (int j = type[i]; j < MONEY; j++) {
  14. Min[j] = min(Min[j], Min[j - type[i]] + 1);//递推式
  15. }
  16. }
  17. }
  18. int main()
  19. {
  20. int m = 0;
  21. cin >> m;
  22. minCoin();
  23. cout << Min[m] << endl;
  24. return 0;
  25. }

打印最少硬币的组合

在最少硬币问题中,增加一个记录表minPath[i],记录金额 j 需要的最后一个硬币,利用minPath倒推,就能得到所有的硬币。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MONEY = 251;//定义最大金额
  4. const int VALUE = 5;//5种硬币
  5. int type[VALUE] = { 1,5,10,50,100 };//5种面值
  6. int Min[MONEY];//每个金额对应最少的硬币数量
  7. int minPath[MONEY] = { 0 };//记录最小硬币的路径
  8. void minCoin() {
  9. for (int i = 0; i < MONEY; i++) {
  10. Min[i] = INT_MAX;//初始值为无穷大
  11. }
  12. Min[0] = 0;
  13. for (int i = 0; i < VALUE; i++) {
  14. for (int j = type[i]; j < MONEY; j++) {
  15. if (Min[j] > Min[j - type[i]] + 1) {
  16. minPath[j] = type[i];//记录
  17. Min[j] = Min[j - type[i]] + 1;//递推式
  18. }
  19. }
  20. }
  21. }
  22. //打印硬币组合
  23. void printCoin(int* minPath, int s) {
  24. while (s) {
  25. cout << minPath[s] << ' ';
  26. s = s - minPath[s];
  27. }
  28. }
  29. int main()
  30. {
  31. int m = 0;
  32. cin >> m;
  33. minCoin();
  34. cout << Min[m] << endl;
  35. printCoin(minPath, m);
  36. return 0;
  37. }

所有硬币组合数1

有n种硬币,面值为v1,v2,...,vn,数量无限。输入非负整数s,选用硬币,使其和为s。要求输出可能的硬币组合。

计算所有硬币组合数:

初始状态:金额为0,组合数为0

金额为i时,dp[i]=dp[i-type[0]]+dp[i-type[1]]+dp[i-type[2]]....

金额为i,可以是dp[i-1]加1个1元硬币,dp[i-5]加1个5元硬币.......

注:没有考虑硬币数量的限制。

代码如下:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MONEY = 251;//定义最大金额
  4. const int VALUE = 5;//5种硬币
  5. int type[VALUE] = { 1,5,10,50,100 };//5种面值
  6. int dp[MONEY] = { 0 };//每种金额对应的组合数
  7. void countCoin() {
  8. dp[0] = 1;
  9. for (int i = 0; i < VALUE; i++) {
  10. for (int j = type[i]; j < MONEY; j++) {
  11. dp[j] = dp[j] + dp[j - type[i]];
  12. }
  13. }
  14. }
  15. int main()
  16. {
  17. int m = 0;
  18. cin >> m;
  19. countCoin();
  20. cout << dp[m] << endl;
  21. return 0;
  22. }

所有硬币组合数1

有5种面值的硬币,即1、5、10、25、50。输入一个钱数s,输出组合方案的数量。s<=250; num<=100。

dpcoin[i][j]是用j个硬币实现金额i的方案数量。利用dpcoin[i][j]可以找到某金额对应的最少和最多硬币数量。

状态转移方程式:dpcoin[k][j] += dpcoin[k - type[i]][j - 1];

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MONEY = 251;//定义最大金额
  4. const int VALUE = 5;//5种硬币
  5. int type[VALUE] = { 1,5,10,25,50 };//5种面值
  6. //考虑硬币的数目num
  7. const int COIN = 101;//不超过100个硬币
  8. int dpcoin[MONEY][COIN] = {0};//DP转移矩阵
  9. int CoinCombination(int s) {
  10. dpcoin[0][0] = 1;
  11. for (int i = 0; i < VALUE; i++) {
  12. for (int j = 1; j < COIN; j++) {
  13. for (int k = type[i]; k < MONEY; k++)
  14. dpcoin[k][j] += dpcoin[k - type[i]][j - 1];
  15. }
  16. }
  17. int ans[MONEY] = { 0 };
  18. for (int i = 0; i < MONEY; i++)
  19. for (int j = 0; j < COIN; j++)
  20. ans[i] += dpcoin[i][j];//对每个金额计算组合方案数目
  21. return ans[s];
  22. }
  23. int main()
  24. {
  25. int m = 0;
  26. cin >> m;
  27. cout << CoinCombination(m) << endl;
  28. return 0;
  29. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/373140
推荐阅读
相关标签
  

闽ICP备14008679号