动态规划问题解决方法及示例

什么是动态规划

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

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

可以应用动态规划求解的问题主要由四个特点:
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, 
  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
动态规划是一种解决多阶段决策问题的优化方法。它将问题分解为多个子问题,并利用递推关系来计算每个子问题的最优,最终得到整体问题的最优解。 动态规划算法通常包含以下步骤: 1. 定义状态:将问题抽象为一个状态集合,每个状态代表一个问题的解。 2. 定义状态转移方程:找出每个状态之间的递推关系,即当前状态与前一状态之间的关系。 3. 初始化:设置初始状态的值,通常是已知的边界条件。 4. 递推计算:根据状态转移方程,从初始状态开始逐步计算出所有状态的值。 5. 最优解:根据问题的要求,从最终状态中选取最优解。 下面是一个动态规划算法示例,用于解决背包问题: ```python def knapsack(weights, values, capacity): n = len(weights) # 初始化动态规划表 dp = [[0] * (capacity + 1) for _ in range(n + 1)] for i in range(1, n + 1): for j in range(1, capacity + 1): if weights[i-1] <= j: # 选择当前物品 choose = values[i-1] + dp[i-1][j-weights[i-1]] # 不选择当前物品 not_choose = dp[i-1][j] dp[i][j] = max(choose, not_choose) else: # 当前物品无法放入背包 dp[i][j] = dp[i-1][j] # 返回最优解 return dp[n][capacity] ``` 在这个示例中,`weights` 是物品的重量列表,`values` 是物品的价值列表,`capacity` 是背包的容量。函数 `knapsack` 返回背包可以装下的最大价值。 这个算法使用一个二维的动态规划表 `dp` 来保存每个子问题的最优解。通过填充这个表,最后可以得到背包问题的最优解。 注意,这只是一个简单的示例,实际应用中可能会有更复杂的状态定义和状态转移方程。动态规划算法的关键是找到递推关系和合适的状态定义,以及正确地填充动态规划表。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值