凑硬币问题

题目详情为:有面值为1元、3元和5元的硬币若干枚,如何用最少的硬币凑够11元?

最近在学习一些重要算法,作为五大算法之一的动态规划法,自然要认真学习,这是一道典型的动态规划问题,这里使用动态规划法的思想来解题;

我们用d(i)=j来表示凑够i元最少需要j个硬币,通过题目,很容易得到:当i=0时,d(0)=0, 表示凑够0元最小需要0个硬币; 当i=1时,只有面值为1元的硬币可用, 因此我们拿起一个面值为1的硬币,接下来只需要凑够0元即可,而这个是已经知道答案的, 即d(0)=0,则有d(1) = d(1 - 1) + 1 = 1,凑够1元最少需要1个硬币,当i = 2时,d(2) = d(2 - 1) + 1= d(1) +1=2, 当i = 3时,d(3) = min{d(3 - 1) + 1 , d(3 - 3) + 1} = min(3, 1) = 1;动态规划算法通常基于一个递推公式及一个或多个初始状态。在这里d(i) 就是状态,通过分析推导的过程,可以得到,针对面值为1,3,5的硬币,可以得到递推公式(状态转移方程)为:

d(i) = min{ d(i - Vj) + 1} ,i >= Vj。

在动态规划中,得到了该问题的状态及其状态转移方程,问题已经解决了一大半了,然后,在分析的过程中,并不能一眼就看出递推公式,它需要更多的练习和更多的实践积累的,并不是一朝一夕能做到的,况且动态规划的关键就是找到状态和状态转移方程,那么容易找到,就不是动态规划了,就不是难点了。根据这个公式,我们可以比较轻易的写出实现的代码:

/*@动态规划练习题

如果我们有面值为1元、3元和5元的硬币若干枚,如何用最少的硬币凑够11元?*/#include#include#include

int DP_leastcoin(const int coin[], intmoney)

{int *d = (int *)malloc(sizeof(int) * (money + 1));

memset(d,0, sizeof(int) *money);int iterx = 0, itery = 0;int MIN = 0;int result = 0;

d[0] = 0;for(iterx = 1; iterx <= money; iterx++)

{for(itery = 0; itery < 3 && iterx >= coin[itery]; itery++)

{if(itery == 0)

{

MIN= d[iterx - coin[itery]] + 1;

}else if(MIN > (d[iterx - coin[itery]] + 1))

{

MIN= (d[iterx - coin[itery]] + 1);

}

}

d[iterx]=MIN;

}

printf("要凑的钱 MIN\n");for(iterx = 0; iterx <= money; iterx++)

{

printf("序号%-3d : %d\n", iterx, d[iterx]);

}

result=d[money];

free(d);returnresult;

}int main(void)

{const int coin[3] = {1, 3, 5};

printf("\nThe result is %d \n", DP_leastcoin(coin, 112));return 0;

}

View Code

在研究凑硬币问题的时候,我把硬币的面值换为2,3,5,然后依旧使用这个状态转移方程,得到的结果是错的,由此也可以知道,状态转移方程是针对某一问题分析得到的,尽管只是修改了硬币的面值,该方程就不再成立了,首先我们要找到问题所在,是什么问题导致了该方程不再适用。

我们手动分析面值为2,3,5的情况:

d(0) = 0

d(1) = 0

d(2) = 1

d(3) = 1

d(4) = 2

d(5) = 1

d(6) = 2

d(7) = 2

d(8) = 2

d(9) = 3

d(10) = 2

d(11) = 3

我们先来看看面值为2,3,5的结果图片,看看是在哪里开始出错的:

找出两者不一样的值,发现是从序号4开始的,d(4) , d(6) , d(9) , d(11) 这几个不同(当然后续还有其他不同的值),把这些状态代入上面的状态转移方程,看看那哪里不对:

d(4) = min{ d(4 - 3) + 1, d(4 - 2) + 1} = min{ d(1)+1, d(2)+1 }=min(0+1, 1+1) = 1;

问题来了,本来d(4)应该是等于2,由两个面值额外2的硬币凑成,这里怎么会有1呢?1的由来,是d(1)+1 = 1;d(6)也是有问题的,看下面

d(6) = min{d(6 - 5)+1, d(6 - 3)+1, d(6 - 2)+1}= min(d(1)+1, d(3)+1, d(4)+1}=min(1, 2, 2);

问题还是在d(1)上面,至于后面的d(9) 和d(11)是因为使用了错误的d(6)和d(4)才错的,那这个方程的罪魁祸首就是d(1)咯?

假设我们把d(4) 和 d(6) 都纠正过来,即d(4)= 2, d(6) = 2,那么结果又如何,你可以自己从新列一遍,从d(6)开始,后面都是正确的。这里把我纠正的图片发一下,面值为2,3,5的,我给的需要凑得钱值是112,设一个更大的值,容易排查错误情况:

上面没有把数据全部列出来。我检查了一下,对于面值为2,3,5的情况,没有发现错误的。

很奇怪,这样一改程序就正确了,我猜想,把面值1,3,5的状态转移方程,拿到面值为2,3,5问题里面就出错,而修改一下(2,3,5)问题的前面某些值d(4)和d(6),状态方程依旧适用,主要原因还是在面值为1的硬币上,由于存在面值为1的情况,假设要凑的钱数为N,那么只要N>0,肯定可以凑出来,把硬币面值换为(2,3,5),那要凑出1块钱是不可能的,所以d(1)+1就有了问题,因为你无法凑到1块钱,是不能使用d(1)的,把存在d(1)的情况去掉,那结果就是正确的,现在知道为什么是4和6了吧,因为你的面值为2,3,5,一个数减掉2,3,5得到1的数就是3,4,6,所以,d(3), d(4) ,d(6)就是错的,那前面怎么没有指出d(3),因为恰好d(1)的结果不影响d(3),尽管如此,还是要把d(1)去掉,方法如下:

d(4) = min{d(4 - 2) + 1}  = min(2) = 2,本来是d(4) = min{d(4 - 2) + 1, d(4 - 3) + 1}  = min(2 , 1) = 1

程序修改十分简单,就在嵌套的for循环里面加上一条语句  “if(iterx - coin[itery] == 1) continue;//当硬币面值没有1时” 即可,如下:

/*@动态规划练习题

如果我们有面值为1元、3元和5元的硬币若干枚,如何用最少的硬币凑够11元?*/#include#include#include

int DP_leastcoin(const int coin[], intmoney)

{int *d = (int *)malloc(sizeof(int) * (money + 1));

memset(d,0, sizeof(int) *money);int iterx = 0, itery = 0;int MIN = 0;int result = 0;

d[0] = 0;for(iterx = 1; iterx <= money; iterx++)

{for(itery = 0; itery < 3 && iterx >= coin[itery]; itery++)

{if(iterx - coin[itery] == 1) continue;//当硬币面值没有1时

if(itery == 0)

{

MIN= d[iterx - coin[itery]] + 1;

}else if(MIN > (d[iterx - coin[itery]] + 1))

{

MIN= (d[iterx - coin[itery]] + 1);

}

}

d[iterx]=MIN;

}

printf("要凑的钱 MIN\n");for(iterx = 0; iterx <= money; iterx++)

{

printf("序号%-3d : %d\n", iterx, d[iterx]);

}

result=d[money];

free(d);returnresult;

}int main(void)

{const int coin[3] = {2, 3, 5};

printf("\nThe result is %d \n", DP_leastcoin(coin, 112));return 0;

}

View Code

啰啰嗦嗦的写了很多,我的表达能力有限,望见谅!此外,希望本博客对大家学习算法能有一点帮助!

ps:把硬币面值换为其他值,可能要重新分析,这个题目也可以用贪心算法实现,但是貌似贪心算法有可能求出来的是局部最优解,我对贪心算法不大会,等后续学习到了,再来讨论!

java动态规划凑硬币问题_动态规划--凑硬币问题相关推荐

  1. java实现多边形游戏问题_动态规划-多边形游戏

    算法思想:动态规划 实际问题:多边形游戏 编写语言:Java 前言 多边形游戏问题是矩阵连乘的最优计算次序问题与凸多边形最优三角剖分问题的推广.我在解决凸多边形最优三角剖分问题时偶然间看到了这个结论, ...

  2. 动态规划java实现数塔问题_动态规划入门_数塔问题

    在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少? 已经告诉你了,这是个DP的题目 ...

  3. java 动态规划找零钱_动态规划之找零钱问题

    找零钱是一个经典的动态规划问题.这种问题,我建议,首先学会暴力解法,然后从暴力解法中优化出动态规划的解法,这样,更能体会动态规划的魅力. 问题描述 有n种不同币值的硬币,硬币数量无限.给定一个数量T, ...

  4. java 最少货币单元组合换钱_动态规划. 换钱的最少货币数和最多方法数

    通过对换钱类题目的学习,我们将了解到 暴力递归及优化方法 记忆搜索(优化一) 动态规划的基本实现方法(优化二) 动态规划的空间优化(优化三) 1. 换钱的最少货币数,货币可重复使用 给定数组arr,a ...

  5. 变种 背包问题_动态规划入门——传说中的零一背包问题

    今天是周三算法与数据结构专题的第12篇文章,动态规划之零一背包问题.在之前的文章当中,我们一起探讨了二分.贪心.排序和搜索算法,今天我们来看另一个非常经典的算法--动态规划.在acm-icpc竞赛领域 ...

  6. sql表中只有子节点的递归_动态规划与静态规划、递归、分治、回溯

    动态规划算是运筹学或者算法中的硬骨头了.不是说算法本身有多难,而是学完用完之后还是感觉到对其领会的不够深入,一种能用其术,不知其道的感觉.在很多教材或者回答中,经常看多将动态规划放在递归这一部分中.当 ...

  7. 【BZOJ1042】硬币购物(动态规划,容斥原理)

    [BZOJ1042]硬币购物(动态规划,容斥原理) 题面 BZOJ Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬 ...

  8. c++矩阵连乘的动态规划算法并输出_算法面试必修课,动态规划基础题型归纳(三)

    动态规划(Dynamic Programming,简称DP),是大家都觉得比较难以掌握的算法.为了应付面试,我们经常会背诵一下DP问题的源码,其实,只要理解了思想,掌握基本的模型,然后再来点写代码的套 ...

  9. 【Java -- 算法】分治算法、动态规划、回溯法、贪心算法

    前言 一句话理解四种算法思想 分治:分而治之,先解决子问题,再将子问题的解合并求出原问题. 贪心:一条路走到黑,选择当下局部最优的路线,没有后悔药. 回溯:一条路走到黑,手握后悔药,可以无数次重来.( ...

  10. 动态规划经典题目-找零钱的最少硬币数

    文章目录 一.题目描述 二.解题思路(朴素版本) 1. 定义状态 2. 定义状态转移方程 3. 初始化 三.代码实现 四.优化 五.执行结果 一.题目描述 ​ 美国的硬币按照面值1, 5, 10, 2 ...

最新文章

  1. 领悟Web设计模式(转)
  2. Vue + Bootstrap|Element UI——模态框被遮罩层遮盖问题解决方案
  3. JSON 之 SuperObject(6): 方法
  4. 深入理解Three.js(WebGL)贴图(纹理映射)和UV映射
  5. 【gateway系列】手把手教你gateway整合nacos注册中心
  6. (52)Verilog HDL下升沿检测
  7. 大神齐聚,算法大赛复赛晋级名单揭晓!
  8. 关于接口测试的一些总结
  9. 各种门锁的内部结构图_逃生门锁,我们的生命之锁!
  10. suse 11 mysql_SUSE11SP3X86_64安装配置mysql-8.0.11(亲测可用,软件均为官网下载)
  11. caj打开文件错误验证服务器,CAJ 打开pdf文件错误(无法读取交叉引用表)的解决方法...
  12. 在sagemath中运行python文件
  13. 【翻译】图解Janusgraph系列-事务详解(Janusgraph Transactions)
  14. tdr 定位公式_时域反射计TDR原理详细解析
  15. SIEBEL功能组件,eScript入门
  16. 解决CMU-15-213-ICS的部分lab在部分64位系统WSL中btest无法运行的问题
  17. HTML5和CSS3 API文档分享
  18. java计算机毕业设计楼宇管理系统源码+数据库+lw文档+系统
  19. oracle 按旬统计并且每月小计 行转列 PIVOT函数 与分组小计 ROLLUP 函数
  20. limits.conf 配置不生效问题排查

热门文章

  1. iis服务器mp4不显示,IIS浏览器无法读取mp4视频的解决方法
  2. vit transformer中的cls_token
  3. excel-LOOKUP函数多条件查找
  4. 论文笔记:OntoED: Low-resource Event Detection with Ontology Embedding
  5. 魅族pro5 刷机 android,魅族 PRO5中文Recovery刷机教程
  6. 2倍研发费用=营销费用,小牛电动“智”在何方?
  7. 昆明计算机设计学院官网,文山高中考不上有什么出路
  8. golang binding tag
  9. 数据结构之队列和栈的应用
  10. 支付宝小程序下单支付接口:40004 ACQ.INVALID_PARAMETER