zoukankan      html  css  js  c++  java
  • 数学基础:三、动态规划2(求解凑齐钱的最小张数)

    凑齐钱的最小张数概念:

    比如只有2块、3块和5块钱若干,问凑齐100块钱最小需要几张钱能凑齐?(20张5块的,所以是20张)

    前面一篇求解编辑距离时,有现成的状态转移方程,可是这种凑齐面值的没有现成的公式,只能自己去推导。

    当然我们可以利用求余数求解,凑齐98块,需要98/5=19…3,所以为19张5块+1张3块(一共20张)

    但这个可能用余数可能更方便,但对于动态归划方法,可能是个思路

    比如只有2、3、7块,用表格推导的过程如下:
    在这里插入图片描述
    而如果只有2、5、9块,它的推导如下:
    在这里插入图片描述
    根据推导过程,写出的算法如下:

    public class Lesson10_1 {
        // 钱币币种可选的值,自己可随意改
        private static final int[] coins = {2, 5, 9};
    
        // 如果不加变量保存,每次都要重复递归计算
        private static Map<Integer, Integer> hasCount = new HashMap<>();
    
        // 传入总金额和可选币种,返回凑够该金额的最小数量,返回null表示没有找到
        // 为null表示凑不齐这个钱(商场买菜要1块钱,可选币种最小值要2块,我们不能傻得给人家2块不找零,此时就是凑不齐)
        public static Integer getCount(int total, int[] coins) {
            // 如果之前已计算过该金额的,直接返回,无需递归调用了
            if (hasCount.containsKey(total)) {
                return hasCount.get(total);
            }
            // 递归减到了负数,也没凑齐,就是没找到
            if (total < 0) {
                return null;
            } else if (total == 0) {// 金额为0,那需要的数量肯定为0
                return 0;
            } else {
                int length = coins.length;
                // 保存可选币种中,每种所需的最小数量
                Integer[] min = new Integer[length];
                for (int i = 0; i < length; i++) {
                    // 比如求凑20块钱,可选值是5块钱,那递归求凑15块+1即可    C20(5) = C15(5) + 1
                    // 再比如求凑18块钱,可选值2块钱,那递归求凑16块+1即可    C18(2) = C16(2) + 1
                    // C n (m) = C n-m (m) + 1
                    Integer tmpResult = getCount(total - coins[i], coins);
                    // 返回值为空,说明递归调用到 if (total < 0) 时返回了空,没有凑够该值
                    min[i] = tmpResult != null ? (tmpResult + 1) : null;
                }
                // 去除空值
                List<Integer> resultList = Arrays.stream(min).filter(e -> e != null).collect(Collectors.toList());
                // 如果不为空,那最小值就是所需的最小个数
                Integer result = resultList.size() > 0 ? resultList.stream().mapToInt(e -> e).min().getAsInt() : null;
                // 放到map中,防止后续重复递归计算
                hasCount.put(total, result);
                return result;
            }
        }
    
        public static void main(String[] args) {
            Integer count = getCount(102, coins);
            System.out.println(count);
        }
    }
    
  • 相关阅读:
    左孩子右兄弟的字典树
    UVA 1401 Remember the Word
    HDOJ 4770 Lights Against Dudely
    UvaLA 3938 "Ray, Pass me the dishes!"
    UVA
    Codeforces 215A A.Sereja and Coat Rack
    Codeforces 215B B.Sereja and Suffixes
    HDU 4788 Hard Disk Drive
    HDU 2095 find your present (2)
    图的连通性问题—学习笔记
  • 原文地址:https://www.cnblogs.com/dulinan/p/12032997.html
Copyright © 2011-2022 走看看