无向图的动态规划——硬币问题

以你之姓@ 2022-05-08 12:36 338阅读 0赞

题目描述:
硬币找零问题描述:现存在一堆面值为 V1、V2、V3 … 个单位的硬币
问最多和最少需要多少个硬币才能找出总值为T个单位的零钱?
输入:
第一行为n,T,表示硬币个数,需要凑的面额,第二行有n个数,表示硬币的面额
输出:
一行,分别为最大最小的数目,用空格分开
示例:
输入 5 63
1、2、5、21、25
输出 63 3
解题思路:
运用动态规划,将 Max【T】和Min【T】用来存储总面额为T时所需要的最多和最少
的硬币,Max【T】=max{Max【T-Vi】+1,Max【T】},Min【T】=min{Min【T-vi】+1,
Min【T】},将min【Vi】初始化为1,将max【vi】初始化为1

-—————————— 作者:braveryCHR 来源:CSDN 原文:https://blog.csdn.net/bravery\_again/article/details/72458067?utm\_source=copy

贪心解决:

关于最少硬币的数目,可以用贪心算法——每次选尽可能大的硬币,直至满足条件。

证明:见参考文章

代码:

  1. #include<iostream>
  2. #include<vector>
  3. #include<stack>
  4. #include<algorithm>
  5. using namespace std;
  6. const int maxnum=100;
  7. int find_less(vector<int> &type,stack<int> &money,int s)
  8. {
  9. int sum=0,bakesum;
  10. int len=type.size();
  11. int i;
  12. for(i=len-1;i>=0;i--)
  13. {
  14. while(sum<s)
  15. {
  16. sum+=type[i];
  17. money.push(type[i]);
  18. if(sum==s)
  19. return 1;
  20. }
  21. sum-=type[i];
  22. money.pop();
  23. }
  24. return 0;
  25. }
  26. int main()
  27. {
  28. vector<int> type;//存钱的种类
  29. stack<int> money;//存已经放入的钱
  30. int i,n,s;//用于记数,钱的种类数,总金额
  31. int tmp;
  32. //输入
  33. cin>>n;
  34. for(i=0;i<n;i++)
  35. {
  36. cin>>tmp;
  37. type.push_back(tmp);
  38. }
  39. cin>>s;
  40. sort(type.begin(),type.end());//将面额从小到大排序
  41. if(find_less(type,money,s))
  42. {
  43. while(!money.empty())
  44. {
  45. tmp=money.top();
  46. cout<<tmp<<" ";
  47. money.pop();
  48. }
  49. }
  50. else
  51. cout<<"no way";
  52. return 0;
  53. }

动态规划——图:

开始的时候,怎么也想不出来咋可以用图来解决。后来想通了(如下图所示)。

70

用递归的方式:

  1. #include<iostream>
  2. #include<vector>
  3. #include<algorithm>
  4. #include<climits>
  5. using namespace std;
  6. const int INF=10000;
  7. const int maxmoney=100;
  8. int Max[maxmoney];
  9. int Min[maxmoney];
  10. vector<int> type;
  11. int n;
  12. int minnum(int s)
  13. {
  14. if(Min[s]!=-1)
  15. return Min[s];
  16. Min[s]=INF;
  17. for(int i=0; i<n; i++)
  18. if(s>=type[i])
  19. Min[s]=min(Min[s],minnum(s-type[i])+1);
  20. return Min[s];
  21. }
  22. int maxnum(int s)
  23. {
  24. if(Max[s]!=-1)
  25. return Min[s];
  26. Max[s]=-INF;
  27. for(int i=0; i<n; i++)
  28. if(s>=type[i])
  29. Max[s]=max(Max[s],maxnum(s-type[i])+1);
  30. return Max[s];
  31. }
  32. int main()
  33. {
  34. int i,m;
  35. cin>>n>>m;//n表示零钱的种类,m表示总金额
  36. int tmp;
  37. for(i=0;i<n;i++)
  38. {
  39. cin>>tmp;
  40. type.push_back(tmp);
  41. }
  42. sort(type.begin(),type.end());
  43. Max[0]=0;Min[0]=0;
  44. for(i=1;i<=m;i++)
  45. {
  46. Max[i]=-1;
  47. Min[i]=-1;
  48. }
  49. cout<<minnum(m)<<" "<<maxnum(m);
  50. }

用递推的方式:

  1. #include<iostream>
  2. #include<vector>
  3. #include<algorithm>
  4. #include<climits>
  5. using namespace std;
  6. const int INF=10000;
  7. const int maxmoney=100;
  8. int Max[maxmoney];
  9. int Min[maxmoney];
  10. int main()
  11. {
  12. int i,n,m;
  13. vector<int> type;
  14. cin>>n>>m;//n表示零钱的种类,m表示总金额
  15. int tmp;
  16. for(i=0;i<n;i++)
  17. {
  18. cin>>tmp;
  19. type.push_back(tmp);
  20. }
  21. sort(type.begin(),type.end());
  22. Max[0]=0;Min[0]=0;
  23. for (int i=1;i<=m;++i)
  24. {
  25. Min[i]=INF; //初始化为最大
  26. Max[i]=-INF; //初始化为最小
  27. }
  28. int t;
  29. for(t=1;t<=m;t++)
  30. {
  31. for(i=0;i<n;i++)
  32. if(t>=type[i])
  33. {
  34. Max[t]=max(Max[t],Max[t-type[i]]+1);
  35. Min[t]=min(Min[t],Min[t-type[i]]+1);
  36. }
  37. }
  38. cout<<Max[m]<<" "<<Min[m]<<endl;
  39. return 0;
  40. }

参考文章:

某种 找换硬币问题的贪心算法的正确性

证明刘如佳书p164—硬币问题

发表评论

表情:
评论列表 (有 0 条评论,338人围观)

还没有评论,来说两句吧...

相关阅读

    相关 动态规划硬币

    > 题目:几年教师节活动中,公司里为培训讲师提供了不同面值的饮料兑换券(每种面值数量不限),培训讲师可以领取兑换券去食堂兑换鲜榨果汁,要求兑换券和果汁必须等价,姜小虎想要兑换一

    相关 动态规划硬币问题

    凑硬币问题 假设有 1 元,3 元,5 元的硬币若干(无限),现在需要凑出 11 元,问如何组合才能使硬币的数量最少? 用数组d来存储当前每个面值可以对应的合成的最小