动态规划解决01背包问题

01背包

N N N 件物品和一个最多能背重量为 W W W 的背包。第 i i i 件物品的重量是 w e i g h t [ i ] weight[i] weight[i],得到的价值是 v a l u e [ i ] value[i] value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

利用动规五部曲进行求解:

  1. 确定dp数组以及下标的含义
    使用二维数组 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示从下标[0-i]的物品里任意取,放进容量为 j 的背包中的最大价值总和。

  2. 确定递推公式
    动态规划的思想是从上一状态推出当前状态,从 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i1][j] 状态来推 d p [ i ] [ j ] dp[i][j] dp[i][j],即在 $dp[i-1][j] 状态下考虑物品 状态下考虑 物品 状态下考虑物品i$ 的取舍:

    1. 不取物品 i i i d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j] = dp[i-1][j] dp[i][j]=dp[i1][j]
    2. 取物品 i i i:此时背包要留出物品i的重量,所以要找到 从下标 [ 0 − ( i − 1 ) ] [0-(i-1)] [0(i1)]的物品中任意取,放进容量 ( j − w e i g h t [ i ] ) (j-weight[i]) (jweight[i])的背包中的最大价值总和,然后再将物品 i i i放入背包, d p [ i ] [ j ] = d p [ i − 1 ] [ j − w e i g h t [ i ] ] + v a l u e [ i ] dp[i][j] =dp[i-1][j-weight[i]] + value[i] dp[i][j]=dp[i1][jweight[i]]+value[i]
      最终结果是这两种情况下的最大价值:
      d p [ i ] [ j ] = max ⁡ { d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w e i g h t [ i ] ] + v a l u e [ i ] } dp[i][j] = \max{\{dp[i-1][j], dp[i-1][j-weight[i]] + value[i] \}} dp[i][j]=max{dp[i1][j],dp[i1][jweight[i]]+value[i]}
  3. dp数组初始化

    从定义出发,当背包的重量为0时,无法选取任何物品,即对于 d p [ i ] [ 0 ] dp[i][0] dp[i][0]来说全部等于0;
    当仅考虑物品0时,只有当背包的重量大于 w e i g h t [ 0 ] weight[0] weight[0]时才能选取物品0,即对于 d p [ 0 ] [ j ] dp[0][j] dp[0][j]来说,当 j < w e i g h t [ 0 ] j<weight[0] j<weight[0]时, d p [ 0 ] [ j ] = 0 dp[0][j]=0 dp[0][j]=0;当 j ≥ w e i g h t [ 0 ] j≥weight[0] jweight[0]时, d p [ 0 ] [ j ] = v a l u e [ 0 ] dp[0][j]=value[0] dp[0][j]=value[0]

    //声明dp数组,并初始化所有元素=0
    vector<vector<int>> dp(weight.size() + 1, vector<int>(bagWeight + 1, 0));
    
    //初始化do[0][j]
    for (int i = weight[0]; i <= bagWeight; i++) {
      dp[0][i] = value[0];
    }
    
  4. 确定遍历顺序

    由递推公式来看,先遍历物品和先遍历背包均可以,但是先遍历物品更好理解。

  5. 举例推导

int bag01() {
  vector<int> weight = { 1, 3, 4 };
  vector<int> value = { 15, 20, 30 };
  int bagWeight = 4;

  int wsize = weight.size();
  int vSize = value.size();

  vector<vector<int>> dp(wsize + 1, vector<int>(bagWeight + 1, 0));

  //初始化
  for (int i = weight[0]; i <= bagWeight; i++) {
    dp[0][i] = value[0];
  }
  //遍历
  for (int i = 1; i < wsize; i++) {
    for (int j = 0; j <= bagWeight; j++) {
      if (j < weight[i]) dp[i][j] = dp[i - 1][j];
      else
        dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
    }
  }
  cout << dp[wsize - 1][bagWeight] << endl;
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值