`

动态规划算法求解硬币找零问题(Java)

阅读更多

动态规划的基本思想是将待求解问题分解成若干个子问题,先求解子问题,并将这些子问题的解保存起来,如果以后在求解较大子问题的时候需要用到这些子问题的解,就可以直接取出这些已经计算过的解而免去重复运算。保存子问题的解可以使用填表方式,例如保存在数组中。

用一个实际例子来体现动态规划的算法思想——硬币找零问题。

硬币找零问题描述:现存在一堆面值为 V1、V2、V3 … 个单位的硬币,问最少需要多少个硬币才能找出总值为 T 个单位的零钱?假设这一堆面值分别为 1、2、5、21、25 元,需要找出总值 T 为 63 元的零钱。

很明显,只要拿出 3 个 21 元的硬币就凑够了 63 元了。

基于上述动态规划的思想,我们可以从 1 元开始计算出最少需要几个硬币,然后再求 2 元、3元…每一次求得的结果都保存在一个数组中,以后需要用到时则直接取出即可。那么我们什么时候需要这些子问题的解呢?如何体现出由子问题的解得到较大问题的解呢?

其实,在我们从 1 元开始依次找零时,可以尝试一下当前要找零的面值(这里指 1 元)是否能够被分解成另一个已求解的面值的找零需要的硬币个数再加上这一堆硬币中的某个面值之和,如果这样分解之后最终的硬币数是最少的,那么问题就得到答案了。

单是上面的文字描述太抽象,先假定以下变量:

values[] : 保存每一种硬币的币值的数组
valueKinds :币值不同的硬币种类数量,即values[]数组的大小
money : 需要找零的面值
coinsUsed[] : 保存面值为 i 的纸币找零所需的最小硬币数

算法描述:

当求解总面值为 i 的找零最少硬币数 coinsUsed[ i ] 时,将其分解成求解 coinsUsed[ i – cents]和一个面值为 cents 元的硬币,由于 i – cents < i , 其解 coinsUsed[ i – cents] 已经存在,如果面值为 cents 的硬币满足题意,那么最终解 coinsUsed[ i ] 则等于 coinsUsed[ i – cents] 再加上 1(即面值为 cents)的这一个硬币。

下面用代码实现并测试一下:

  1. public class CoinsChange {  
  2.     /**  
  3.      * 硬币找零:动态规划算法  
  4.      *   
  5.      * @param values  
  6.      *            :保存每一种硬币的币值的数组  
  7.      * @param valueKinds  
  8.      *            :币值不同的硬币种类数量,即coinValue[]数组的大小  
  9.      * @param money  
  10.      *            :需要找零的面值  
  11.      * @param coinsUsed  
  12.      *            :保存面值为i的纸币找零所需的最小硬币数  
  13.      */ 
  14.     public static void makeChange(int[] values, int valueKinds, int money,  
  15.             int[] coinsUsed) {  
  16.  
  17.         coinsUsed[0] = 0;  
  18.         // 对每一分钱都找零,即保存子问题的解以备用,即填表  
  19.         for (int cents = 1; cents <= money; cents++) {  
  20.  
  21.             // 当用最小币值的硬币找零时,所需硬币数量最多  
  22.             int minCoins = cents;  
  23.  
  24.             // 遍历每一种面值的硬币,看是否可作为找零的其中之一  
  25.             for (int kind = 0; kind < valueKinds; kind++) {               
  26.                 // 若当前面值的硬币小于当前的cents则分解问题并查表  
  27.                 if (values[kind] <= cents) {  
  28.                     int temp = coinsUsed[cents - values[kind]] + 1;  
  29.                     if (temp < minCoins) {  
  30.                         minCoins = temp;  
  31.                     }  
  32.                 }  
  33.             }  
  34.             // 保存最小硬币数  
  35.             coinsUsed[cents] = minCoins;  
  36.  
  37.             System.out.println("面值为 " + (cents) + " 的最小硬币数 : " 
  38.                     + coinsUsed[cents]);  
  39.         }  
  40.     }  
  41.       
  42.     public static void main(String[] args) {  
  43.  
  44.         // 硬币面值预先已经按降序排列  
  45.         int[] coinValue = new int[] { 25211051 };  
  46.         // 需要找零的面值  
  47.         int money = 63;  
  48.         // 保存每一个面值找零所需的最小硬币数,0号单元舍弃不用,所以要多加1  
  49.         int[] coinsUsed = new int[money + 1];  
  50.  
  51.         makeChange(coinValue, coinValue.length, money, coinsUsed);  
  52.     }  

测试结果:

面值为 1 的最小硬币数 : 1
面值为 2 的最小硬币数 : 2
面值为 3 的最小硬币数 : 3
面值为 4 的最小硬币数 : 4
面值为 5 的最小硬币数 : 1
面值为 6 的最小硬币数 : 2
...
...
面值为 60 的最小硬币数 : 3
面值为 61 的最小硬币数 : 4
面值为 62 的最小硬币数 : 4
面值为 63 的最小硬币数 : 3

 上面的代码并没有给出具体应该是哪几个面值的硬币,这个可以再使用一些数组保存而打印出来。

分享到:
评论

相关推荐

    Java动态规划之硬币找零问题实现代码

    Java动态规划之硬币找零问题实现代码可以通过动态规划的思想来解决硬币找零问题,通过将问题分解成多个子问题,从而避免重复运算,提高算法的效率。 希望这篇文章能够对大家有所帮助。如果您有任何问题或建议,请...

    算法最少硬币问题题目

    - 根据读取的数据初始化 `T` 和 `Coins` 数组,然后执行上述动态规划算法。 - 结果输出到 `output.txt`,包含计算出的最少硬币数,或在无解时输出 `-1`。 在给定的输入文件 `input.txt` 示例中,有 3 种面值的硬币...

    什么是动态规划(Dynamic Programming)?动态规划的意义是什么? - 知乎1

    动态规划(Dynamic Programming,简称DP)是一种用于解决最优化问题的算法思想,它通过将大问题分解为相互重叠的子问题,并存储子问题的解,以避免重复计算,从而达到高效求解的目的。DP的核心在于它能够识别并利用...

    硬币找零问题(使用动态编程)

    在硬币找零问题中,我们可以使用动态规划来构建一个解决方案。 首先,我们需要理解动态规划的基本思想。动态规划通过将大问题分解为小问题,然后逐步解决这些小问题,最终得到大问题的解。在硬币找零问题中,我们...

    java算法大全源码包100多种

    - 动态规划与状态转移:如硬币找零问题、剪绳子问题。 - 模拟法:根据题目描述模拟实际过程,求出结果。 这些算法是计算机科学的基础,掌握它们不仅能提升编程能力,还能为面试和解决实际问题提供强大的工具。...

    JS使用贪心算法解决找零问题示例

    但在面对需要全局最优解的问题时,如旅行商问题、最小生成树等,贪心算法就显得力不从心,这时需要采用其他算法,如动态规划、回溯法等。 总的来说,贪心算法是解决某些特定类型问题的有效工具,尤其在面对局部最优...

    All Algorithms implemented in Java..zip

    - Floyd-Warshall算法:求解所有顶点对之间最短路径的动态规划算法。 4. **动态规划**: - 背包问题:0-1背包、完全背包、多重背包等,用于优化决策问题。 - 最长公共子序列(LCS):找到两个序列最长的不相交子...

    确定将一定数量的钱比如100,换成1,2,5,10,20,50元的组合问题(3)

    例如,`CoinToSum3.java`这个文件很可能包含了上述动态规划算法的Java实现。在实际的代码中,可能会定义一个`Coin`类来存储硬币的面值,然后定义一个`change`函数,接收总金额作为参数,返回一个二维数组表示所有...

    东北大学算法分析与设计实验内容代码+报告

    在"找零钱问题"中,假设我们需要找零给定金额,动态规划可以用于确定最少数量的硬币组合。通常,我们会维护一个数组,记录到当前值所需最少硬币数,通过比较使用当前硬币类型和不使用的情况来更新这个数组。 三、...

    找零钱问题的贪心算法.pdf

    贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,...在这种情况下,可能需要使用动态规划等其他算法来求解。然而,对于本问题的设定,贪心算法是有效的,因为它符合问题的贪心选择性质。

    Java版数据结构与算法视频教程地址.txt

    - 应用场景:硬币找零问题、最小生成树问题等。 #### 四、实战案例 - **项目案例**:使用Java实现一个简单的在线购物车系统。 - 数据结构:使用哈希表来存储商品信息,使用链表来管理用户的购物车。 - 算法应用...

    确定将一定数量的钱比如100,换成1,2,5,10,20,50元的组合问题(2)

    标题中的“确定将一定数量的钱比如100,换成1,2,5,10,20,50元的组合问题(2)”是指一个经典的动态规划问题,也被称为“找零问题”或者“硬币找零问题”。在这个问题中,目标是找到使用特定面值的硬币(1元,2...

    acm.timus.ru-solutions:这些是我对ACM.TIMUS.RU问题的解决方案

    Java代码可能需要用到数学库如BigInteger来处理大整数运算,或者用动态规划解决硬币找零问题等。 8. **模拟与暴力求解**:对于一些简单或特定条件下的问题,可能直接采用模拟或暴力穷举的方法求解,尽管效率较低,...

    LeetCode解决方案

    6. **动态规划**:动态规划是一种解决最优化问题的方法,通过将大问题分解为小问题来求解。经典例子有斐波那契数列、背包问题、最长递增子序列等。 7. **回溯法**:这是一种试探性的解决问题的方法,通过不断地尝试...

Global site tag (gtag.js) - Google Analytics