java动态规划算法——硬币找零问题实例分析

本文实例讲述了java动态规划算法——硬币找零问题。分享给大家供大家参考,具体如下:

问题描述

现在有3种硬币分别为:1元,5元,10元,现在给你63元,让你全部换成硬币,求出最小硬币数量,也就是说,怎么用最少的硬币数凑成63元。

分析问题

解决这个问题,我们可以将这个大问题分成若干个小问题,自下而上解决问题。

1元对应的最小硬币数是1

2元对应的最小硬币数是2

3元对应的最小硬币数是3

4元对应的最小硬币数是4

……

63元对应的最小硬币数是XXX

假设我们将前边计算出的金额对应的最小硬币数像备忘录一样记录下来,那么后边金额对应的最小硬币数的就好说了,为什么?

举例:假设你要求63的最小硬币数,那么你需要这样计算:63-1=62、63-5=58、63-10=53。假设62、58、53对应的最小硬币数已经被你记录在了备忘录数组。这时候你只需要找出62、58、53中谁对应的最小硬币数最小,然后加1,就是63对应的最小硬币数。因为63比62、58、53都大,最好的情况无非就是在62、58、53中找出最小的一种情况加1,这就是最优解!

按照这种备忘录思想,我们进行编程。首先将我们要处理的数据转换成数组和必要参数。

int[] coins = { 1 , 5 , 10 }; //硬币面额数组
int adm = 63; //要求的金额
int[] money = new int[63+1]; //金额数组,也就是备忘录数组

说明:money数组就是备忘录数组,例如:money[0]对应0,money[1]对应1,money[2]对应2……

接下来,将我们上边的解题思路抽象成函数,函数中无非就是:循环,判断,赋值……如何利用这些逻辑语句,将我们的思路描述出来,这是最难的,因为要做到滴水不漏,情况都要考虑周全,一步错结果就错,这需要长久锻炼抽象逻辑思维。我比较习惯的方式是边看代码,边关联结题思路,然后模仿,代码中有注释,大家边看边分析吧:

public static void main(String[] args) {

 int[] coins = {1,5,10};
 int money = 63;

 changeMoney(coins,money);
}

/**
 * 硬币找零算法,备忘录方法
 * @param coins 硬币面额数组
 * @param money 目标金额
 */
public static void changeMoney( int[] coins , int money ) {
 //备忘录数组,一一对应
 int[] memo = new int[money + 1];
 //0元对应的最小硬币数是0
 memo[0] = 0;

 System.out.println( "金额\t" + "对应的最小硬币数" );
 //遍历备忘录数组,为每个金额记录他的最小硬币数,我们从1元开始
 for( int currentMoney = 1 ; currentMoney <= money ; currentMoney++ ) {
 //默认最小硬币数就是当前金额的本身
 //举例:63元最多就是63个1元的硬币呗
 int minCoins = currentMoney;
 //遍历硬币面额数组,找到前边所能找到的最小硬币数加1
 for( int coinKind = 0 ; coinKind < coins.length ; coinKind++ ) {
 //只有当前金额大于等于某个硬币面额的时候才可以用这种方法
      //举例:5-1=4,5-5=0,5-10=-5,我们没有-5元好吧……
 if( currentMoney >= coins[coinKind] ) {
 //我们在备忘录中查找之前的金额对应的最小硬币数
 //如果能查到就在它的基础上加1
 int tempCoins = memo[currentMoney - coins[coinKind]] + 1;
 //找到几种情况中最小的硬币数
 //举例:63元 tempConis
 //可以是memo[63-1]+1、memo[63-5]+1、memo[63-10]+1
 //我们要找到最小的
 if( tempCoins < minCoins ) {
  minCoins = tempCoins;
 }
 }
 }
 //找到当前金额对应的最小硬币数,我们将它记录在备忘录中
 memo[currentMoney] = minCoins;

 System.out.println( currentMoney + "\t" + memo[currentMoney] );
 }
}

运行结果

金额        对应的最小硬币数
1        1
2        2
3        3
4        4
5        1
6        2
7        3
8        4
9        5
10        1
11        2
12        3
13        4
14        5
15        2
16        3
17        4
18        5
19        6
20        2
21        3
22        4
23        5
24        6
25        3
26        4
27        5
28        6
29        7
30        3
31        4
32        5
33        6
34        7
35        4
36        5
37        6
38        7
39        8
40        4
41        5
42        6
43        7
44        8
45        5
46        6
47        7
48        8
49        9
50        5
51        6
52        7
53        8
54        9
55        6
56        7
57        8
58        9
59        10
60        6
61        7
62        8
63        9

更多关于java算法相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

(0)

相关推荐

  • Java基于动态规划法实现求最长公共子序列及最长公共子字符串示例

    本文实例讲述了Java基于动态规划法实现求最长公共子序列及最长公共子字符串.分享给大家供大家参考,具体如下: 动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. [问题] 求两字符序列的最长公共字符子序列 问题描述:字符

  • Java算法之最长公共子序列问题(LCS)实例分析

    本文实例讲述了Java算法之最长公共子序列问题(LCS).分享给大家供大家参考,具体如下: 问题描述:一个给定序列的子序列是在该序列中删去若干元素后得到的序列.确切地说,若给定序列X= { x1, x2,-, xm},则另一序列Z= {z1, z2,-, zk}是X的子序列是指存在一个严格递增的下标序列 {i1, i2,-, ik},使得对于所有j=1,2,-,k有 Xij=Zj.例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,

  • Java基于分治算法实现的棋盘覆盖问题示例

    本文实例讲述了Java基于分治算法实现的棋盘覆盖问题.分享给大家供大家参考,具体如下: 在一个2^k * 2^k个方格组成的棋盘中,有一个方格与其它的不同,若使用以下四种L型骨牌覆盖除这个特殊方格的其它方格,如何覆盖.四个L型骨牌如下图: 棋盘中的特殊方格如图: 实现的基本原理是将2^k * 2^k的棋盘分成四块2^(k - 1) * 2^(k - 1)的子棋盘,特殊方格一定在其中的一个子棋盘中,如果特殊方格在某一个子棋盘中,继续递归处理这个子棋盘,直到这个子棋盘中只有一个方格为止如果特殊方格不

  • Java矩阵连乘问题(动态规划)算法实例分析

    本文实例讲述了Java矩阵连乘问题(动态规划)算法.分享给大家供大家参考,具体如下: 问题描述:给定n个矩阵:A1,A2,...,An,其中Ai与Ai+1是可乘的,i=1,2...,n-1.确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少.输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数. 问题解析:由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序.这种计算次序可以用加括号的方式来确定.若一个矩阵连乘积的计算次序完全确

  • Java面试之动态规划与组合数

    最近在刷力扣上的题目,刷到了65不同路径,当初上大学的时候,曾在hihocoder上刷到过这道题目,但是现在已经几乎全忘光了,大概的知识点是动态规划,如今就让我们一起来回顾一下. 从题目说起 题目原文是: 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为"Finish"). 问总共有多少条不同的路径? 例如,上图是一个7 x 3 的网格.有多少可能

  • Java实现的猴子吃桃问题算法示例

    本文实例讲述了Java实现的猴子吃桃问题算法.分享给大家供大家参考,具体如下: 猴子吃桃问题 概述:猴子第一天摘下N个桃子,当时就吃了一半,还不过瘾,就又吃了一个:第二天又将剩下的桃子吃掉了一半,又多吃了一个:以后每天都吃前一天身下的一半零一个,到第n天再想吃的时候就只剩下一个桃子了,求第一天共摘了多少个桃子? 思路及演算步骤(求出共摘多少桃子的函数表达式): 离现在的天数作为变量 f(1) = 1 (剩下桃子的数目) f(2) = f(3) - (吃掉了一些) =   f(3) -(f(3)/

  • 浅谈java实现背包算法(0-1背包问题)

    0-1背包的问题 背包问题(Knapsack problem)是一种组合优化的NP完全问题.问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高.问题的名称来源于如何选择最合适的物品放置于给定背包中. 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放. 用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值.则其状态转移方程便是: f[i][v]=max{ f[i-1][v], f

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

    动态规划的基本思想是将待求解问题分解成若干个子问题,先求解子问题,并将这些子问题的解保存起来,如果以后在求解较大子问题的时候需要用到这些子问题的解,就可以直接取出这些已经计算过的解而免去重复运算.保存子问题的解可以使用填表方式,例如保存在数组中. 用一个实际例子来体现动态规划的算法思想--硬币找零问题. 问题描述: 假设有几种硬币,并且数量无限.请找出能够组成某个数目的找零所使用最少的硬币数.例如几种硬币为[1, 3, 5], 面值2的最少硬币数为2(1, 1), 面值4的最少硬币数为2(1,

  • Java数据结构及算法实例:汉诺塔问题 Hanoi

    /** * 汉诺塔大学的时候就学过,但是根本没搞明白,唯一知道的就是要用递归的方法来求解. * 问题描述: * 有三根杆子A,B,C.A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小. * 要求按下列规则将所有圆盘移至C杆: * 1.每次只能移动一个圆盘: * 2.大盘不能叠在小盘上面. * 提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆, * 但都必须尊循上述两条规则. * 问:如何移?最少要移动多少次? * 解决方法: * 假设只有2个盘子,柱子分别是A, B, C柱

  • Java动态规划之编辑距离问题示例代码

    动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移.一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划. 动态规划实际上是一类题目的总称,并不是指某个固定的算法.动态规划的意义就是通过采用递推(或者分而治之)的策略,通过解决大问题的子问题从而解决整体的做法.动态规划的核心思想是巧妙的将问题拆分成多个子问题,通过计算子问题而得到整体问题的解.而子问题又可以拆分成更多的子问题,从而用类似递推迭代的方法解决要求的问题.问题描述: 对于序列S和T,

随机推荐