什么是动态规划

动态规划是求解决策过程最优化的数学方法。如果一个问题可以分解成若干个子问题,并且子问题之间还有重叠的更小的子问题,就可以考虑用动态规划来解决这个问题。

应用动态规划之前要分析能否把大问题分解成小问题,分解后的每个小问题也存在最优解。如果将小问题的最优解组合起来能够得到整个问题的最优解,那么就可以使用动态规划解决问题。

可以应用动态规划求解的问题主要由四个特点:

1. 问题是求最优解

2. 整体问题的最优解依赖于各个子问题的最优解

3. 大问题分解成若干小问题,这些小问题之间还有相互重叠的更小的子问题

4. 从上往下分析问题,从下往上求解问题

分析

例:给定数组arr,arr中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求换钱有多少种方法。

思路及优化方法:

这里写图片描述

暴力搜索方法

arr={5、10、25、1},aim=1000

1、用0张5元的货币,让[10,25,1]组成剩下的1000,最终方法数记为res1

2、用1张5元的货币,让[10,25,1]组成剩下的995,最终方法数记为res2

3、用2张5元的货币,让[10,25,1]组成剩下的990,最终方法数记为res3

……

201、用200张5元的货币,让[10,25,1]组成剩下的0,最终方法数记为res201

最终结果为res1+res2+…+res201。

定义递归函数:int p1(arr, index, aim),返回用arr[index]至arr[N-1]的货币面值组成面值aim的方法数。

public class DynamicProgramming {
   
    public int coins1(int[] arr, int aim) {
        if (arr == null || arr.length == 0 || aim < 0) {
            return 0;
        }
        return process(arr, 0, aim);
    }
    /**
     * 即上述p1方法
     */
    public int process(int[] arr, int index, int aim) {
        int res = 0;
        if (arr.length == index) {
            return (aim == 0 ? 1 : 0);
        }
        for (int i = 0; arr[index] * i <= aim; i++) {
            // arr[index]选i张时,让剩下的货币组成aim-arr[index]*i面额的方法数,即res_i
            // 总的方法数即为res_0+res_1+...+res_(aim/arr[index])
            res += process(arr, index + 1, aim - arr[index] * i);
        }
        return res;
    }
}

优点:简单方便

缺点:重复计算导致多余的递归,最终导致效率低下

如果已经使用0张5元和1张10元的情况下,后续将求:process(arr, 2, 990);

但是如果已经使用了2张5元和0张十元时,也将要求:process(arr, 2, 990);

就会造成重复计算。

记忆搜索方法

思路:使用HashMap记录计算结果。

public class DynamicProgramming {
   
    /**
     * 二维数组map[i][j]的结果代表process(arr, i, j)的返回结果
     */
    private int[][] map;
    public int coins1(int[] arr, 


本文由转载于互联网,如有侵权请联系删除!