01背包问题dp数组理解dp[i][j-weight]


一、01背包是什么?

有 n 件物品和一个最多能背重量为 w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。
每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
0 1就表示物品的两种状态(0:不放进去,1:放进背包)

二、例子

现有一个背包最大容量为4
现有如下物品:
在这里插入图片描述
问背包能装下的最大价值是多少?

三、解决思路dp(动态规划)

动规五部曲

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

2.确定递推公式
dp[i][j]的含义:从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

那么可以有两个方向推出来dp[i][j],

  • 不放物品i:由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]。(其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以背包内的价值依然和前面相同。)
  • 放物品i:由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值

之前一直不理解为什么要用到 j-weight, 后面想明白,这一个主要是为了保证 j > weight(也就是说背包的容量大于当前物品的重量),确保背包的容量能放进物品 i 。

所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

3.dp数组如何初始化

在这里插入图片描述

4.确定遍历顺序

先遍历 物品还是先遍历背包重量呢?
其实都可以
下面是两种遍历顺序的代码

//先物品后背包
// weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); 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]);

    }
}
//先背包后物品
// weight数组的大小 就是物品个数
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
    for(int i = 1; i < weight.size(); i++) { // 遍历物品
        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]);
    }
}

5.举例推导dp数组

在这里插入图片描述

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码实现了一个动态规划的 0-1 背包问题背包问题是指有一个容量为 capacity 的背包,同时有 n 个物品,每个物品有一个重量和一个价值。我们需要选择一些物品放入背包中,使得它们的总重量不超过容量,同时总价值最大化。 代码中的 items 是一个二元组列表,每个二元组表示一个物品的重量和价值。capacity 表示背包的容量。 首先,我们定义一个 n+1 行,capacity+1 列的二维数组 dp,其中 dp[i][j] 表示前 i 个物品放入容量为 j 的背包中所能获得的最大价值。初始化时,将 dp 的第一行和第一列全部初始化为 0。 然后,我们使用两个循环遍历每个物品,并计算 dp[i][j] 的值。如果当前物品的重量 weight 大于背包的容量 j,则无法将该物品放入背包中,此时 dp[i][j] 的值与 dp[i-1][j] 相同;否则将该物品放入背包中,dp[i][j] 的值为 dp[i-1][j](不放入该物品)和 dp[i-1][j-weight]+value(放入该物品)中的最大值。 最后,我们需要构造最优解。从 dp[n][capacity] 开始,逆序遍历 dp 数组,如果 dp[i][j] 不等于 dp[i-1][j],则说明第 i 个物品被放入了背包中,将 "1" 添加到 selected_items 中并将 j 减去该物品的重量;否则第 i 个物品没有被放入背包中,将 "0" 添加到 selected_items 中。遍历完成后,返回 selected_items,其中的 "1" 表示对应的物品被选择,"0" 表示未被选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值