动态规划总结+01背包问题算法

1 动态规划题目的特征

动态规划问题一定具备以下三个特征:
重叠子问题:在穷举的过程中(比如通过递归),存在重复计算的现象;
无后效性:子问题之间的依赖是单向性的,某阶段状态一旦确定,就不受后续决策的影响;
最优子结构:子问题之间必须相互独立,或者说后续的计算可以通过前面的状态推导出来。

2 写出状态转移方程

动态规划问题的核心是写出正确的状态转移方程,为了写出它,我们要先确定以下几点:
初始化状态:由于动态规划是根据已经计算好的子问题推广到更大问题上去的,因此我们需要一个“原点”作为计算的开端;
状态:找出子问题与原问题之间会发生变化的变量,这个变量就是状态转移方程中的参数;
决策:改变状态,让状态不断逼近初始化状态的操作。这个决策,就是状态转移方程状态转移的方向。

3 编码

  1. 定义状态转移参数
  2. 设计备忘录
  3. 实现状态转移方程

4 举例: 0-1背包问题

给你一个可放总重量为 W 的背包和 N 个物品,对每个物品,有重量 w 和价值 v 两个属性,那么第 i 个物品的重量为 w[i],价值为 v[i]。现在让你用这个背包装物品,问最多能装的价值是多少?

状态转移方程

在这里插入图片描述

递归的写法
/* 
 * tn: traversed n,即已经遍历过的物品;
 * rw: reserved w,即背包还能容量的重量。
 */
DP(int tn, int rw) {
  // 当遍历完所有物品时,就该返回 0 了,因为没有物品也就没有价值了
  if tn < 0
    return 0
  
  // 当背包还能容纳的重量已经小于当前物品的重量时,显然这个物品不能放入背包
  if rw < w[tn]
    return DP(tn - 1, rw)
  
  // 作出决策,该不该放入物品:
  //   1. 放入:那么价值是 DP(tn - 1, rw - w[tn]);
  //   2. 不放入:那么价值是 DP(tn - 1, rw)。
  return max(DP(tn - 1, rw), DP(tn - 1, rw - w[tn]) + v[tn])
}
动态规划的写法

状态转移参数: 变化的重量 , 变化的容量
于是使用双层循环计算子问题, 通过决策从子问题中求出最值的答案
0-1背包问题用max函数来决策, 动态规划问题的核心就是找出决策函数

int dp(int[] w, int[] v, int N, int W) {
    // 创建备忘录
    int[][] dp = new int[N+1][W+1];
  
    // 初始化状态
    for (int i = 0; i < N + 1; i++) { dp[i][0] = 0; }
    for (int j = 0; j < W + 1; j++) { dp[0][j] = 0; }
  
    for (int tn = 1; tn < N + 1; tn++) { // 遍历每一件物品
    for (int rw = 1; rw < W + 1; rw++) { // 背包容量有多大就还要计算多少次
        if (rw < w[tn]) {
          // 当背包容量小于第tn件物品重量时,只能放入前tn-1件
          dp[tn][rw] = dp[tn-1][rw];
        } else {
                // 当背包容量还大于第tn件物品重量时,进一步作出决策
          dp[tn][rw] = Math.max(dp[tn-1][rw], dp[tn-1][rw-w[tn]] + v[tn]);
        }
      }
    }
  
  return dp[N][W];
}

int solveDP() {
  int N = 3, W = 5; // 物品的总数,背包能容纳的总重量
  int[] w = {0, 3, 2, 1}; // 物品的重量
  int[] v = {0, 5, 2, 3}; // 物品的价值
  
  return dp(w, v, N, W); // 输出答案
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值