zoukankan      html  css  js  c++  java
  • 动态规划 如何用最少的硬币枚数找钱?

    遇到问题后,可以先用回溯法解决,虽然时间复杂度比较高,但是容易进行思考和分析。

    之后再根据动态规划的1个模型,3个特性,看是问题是否满足,如果满足,再用2个方法找到问题的动态规划版本,降低时间复杂度(一般会提升一些空间复杂度)

    public class Coins {
        //动态规划特点:
        //1个模型,3个特性,2个方法
        //1个模型,3个特性
        //满足了就可以用动态规划求解
        //1模型:阶段决策最优解模型
        //3特性:
        //1.重复子问题 (不同的决策序列,到某个阶段后,会遇到相同的状态)
        //2.无后效性
        //2.1.只关心解决当前阶段子问题,不需要知道之前的状态是怎么推导出来的
        //2.2.前面解决的问题,不受到后面解决的子问题影响其状态
        //3.最优子结构(一个问题的最优解,包含子问题的最优解,要求这个问题的最优解,就化简成了,求这个问题所有子问题的最优解,如果都求解到了,那么这个问题的最优解也就求解到了)
        //
        //2个方法
        //1.状态表
        //回溯法暴力求解(可以配合’子问题状态的记忆‘来修枝)-> 确定状态(子问题由哪几个主要参数决定) - 画递归树 - 找重复子问题 - 画状态转移表(一般是2维表) - 填状态表 - 按照填写过程的逻辑code (- 在此基础上优化空间复杂度 - 状态方程)
        //2.状态方程(类似递归时候写的 递推公式)
        //找最优子结构 -> 写动态方程 - code
    
        //回溯,动态规划,贪心,分治
        //分类:
        // 1.回溯,动态规划,贪心 (求最优解)
        // 2.分治
        // 最初分析问题的时候他们都可以用递归的编程思想(方法)来求出时间复杂度相对较高的初期解决方案
        //能解决的问题 :回溯>动态规划>贪心
        //时间复杂度   :回溯>动态规划>贪心
        //            2^n n*m
    
    
        //1.暴力回溯法求解 O(n^m)//2.用动态规划找给定面值的硬币(最少硬币枚数)
        //返回-1 表示找不开
        public static int getCoinCount(int money, int[] coins, int n) {
            if (check(money, coins, n))
                return -1;
    
            int[] state = new int[money + 1];       //下标:[i]=剩余需要找i元, 值:需要找的硬币枚数
            int[] coinValues = new int[money + 1];  //下标:i剩余需要找i元,值:需要找的每个硬币的币值
            for (int i = 0; i < money + 1; i++)
                state[i] = -1;
            state[money] = 0;
            for (int i = money; i >= 0; i--) {
                if (state[i] == -1)
                    continue; //当前状态无效(没有任何一种找法,可以得到剩余i元的情况)
                for (int j = 0; j < n; j++) {
                    int toMoney = i - coins[j];
                    if (toMoney < 0)
                        continue; //找过头了
                    int coinCount = state[i] + 1;
                    if (state[toMoney] == -1 || state[toMoney] > coinCount) {
                        state[toMoney] = coinCount;
                        coinValues[toMoney] = coins[j];
                        if (toMoney == 0) {
                            System.out.println("toMoney==0  " + coinCount);
                            //其实,可以break出最外层循环了,以最少的硬币枚次找到了合适的钱
                        }
                    }
                }
            }
            if (coinValues[0] != 0) {
                int i = 0;
                while (coinValues[i] != 0) {
                    System.out.println("coinValue(面值): " + coinValues[i]);
                    i += coinValues[i];
                    if (i > money - 1)
                        break;
                }
            }
            return state[0];
        }
    
        private static boolean check(int money, int[] coins, int n) {
            if (money < 0)
                return true;
            if (coins == null)
                return true;
            if (n <= 0)
                return true;
            for (int i = 0; i < n; i++) {
                if (coins[i] <= 0)
                    return true;
            }
            return false;
        }
    
        public static void main(String[] ar) {
            int money = 11;
            int[] coins = new int[]{2, 5, 10, 50};
            System.out.println("币值有 " + Arrays.toString(coins));
    
            int co = 0;
    
            System.out.println("
    ======= 找钱 " + money);
            co = getCoinCount(money, coins, coins.length);
            System.out.println("硬币枚数: " + co);
    
            money = 167;
            System.out.println("
    ======= 找钱 " + money);
            co = getCoinCount(money, coins, coins.length);
            System.out.println("硬币枚数: " + co);

         money = 3;
            System.out.println("
    ======= 找钱 " + money);
            co = getCoinCount(money, coins, coins.length);
            System.out.println("硬币枚数: " + co);

    } }

    输出

    ======= 找钱 11
    coinValue(面值): 5
    coinValue(面值): 2
    coinValue(面值): 2
    coinValue(面值): 2
    硬币枚数: 4

    ======= 找钱 167
    coinValue(面值): 50
    coinValue(面值): 50
    coinValue(面值): 50
    coinValue(面值): 10
    coinValue(面值): 5
    coinValue(面值): 2
    硬币枚数: 6

    ======= 找钱 3
    硬币枚数: -1

  • 相关阅读:
    wpf 打开win8系统软件盘
    wpf DATAgrid模板中button 命令绑定以及命令参数绑定
    <转>WPF 中的绑定
    代码方式给控件添加背景图片(WPF)
    WPF 枚举使用
    wpf 窗体添加背景图片
    c# 读取txt文件中文乱码解决方法
    Kali linux-信息收集-dmitry
    等保2.0所需设备
    Microsoft Dynamics 2013 --Social Pane
  • 原文地址:https://www.cnblogs.com/cyy12/p/12014442.html
Copyright © 2011-2022 走看看