01背包一维数组(倒序遍历)

文章探讨了在解决背包问题时采用倒叙遍历的原因,主要是为了避免物品被重复使用。通过倒叙遍历,可以确保每个物品只被添加一次,同时逐步构建最优解。初始化时,dp数组全为0,通过不断更新,能获取所有dp值并找到最佳组合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 为什么要倒叙遍历背包容量?为了保证每个物品只被添加一次

下面是正向遍历的情况: 

原因:因为dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);dp[j]是通过比较自己与 dp[j - weight[i]] + value[i]的大小获得的,所以要先知道自己的大小,才能比较,所以才需要倒叙遍历。比如y=max(y,x),需要先知道y和x的大小,才能更新y;如果正向遍历y=max(y,x),x是跟上一个y加上物品的价值的,y就会越来越大,物品就被重复使用了。

为什么可以通过倒叙遍历获得前面的值?因为在初始化的时候,dp中的所有元素都初始化成了0,所以最后一个也是0 。比如刚开始dp[4]=0,遍历一次后,dp[4]=max(dp[4],dp[4-1]+15),其中dp[4]和dp[3]都为0,所以得到了dp[4]=15;再通过dp[4]来更新dp[3]的值,以此类推就可以获得所有dp的值,且每个物品都只选用了一次。

### 使用一维数组实现动态规划的01背包问题详解 #### 什么是01背包问题? 01背包问题是经典的动态规划问题之一,其核心在于给定一组物品和一个固定容量的背包,求解能够放入背包的最大价值组合。其中每个物品只能选择一次。 #### 动态规划的核心思想 动态规划是一种通过分解子问题并保存中间结果来解决问题的方法。对于01背包问题,通常会使用二维数组 `dp[i][j]` 来表示前 `i` 个物品在背包容量为 `j` 的情况下的最大价值[^2]。然而,为了节省空间复杂度,可以将其优化为一维数组形式。 #### 一维数组的状态转移方程 在一维数组中,状态转移方程如下: \[ \text{dp}[j] = \max(\text{dp}[j], \text{dp}[j-\text{weight}[i]]+\text{value}[i]) \] 这里的逻辑是从后向前遍历背包容量 \( j \),以确保当前物品只被考虑一次[^5]。 #### 实现细节 以下是具体的一维数组实现方法: 1. **初始化** 创建一个大小为 \( \text{bagsize}+1 \) 的数组 `dp` 并全部初始化为 0,因为当背包容量为 0 时,能获得的价值也为 0。 2. **外层循环** 外层循环用于遍历每一个物品,依次处理它们对不同背包容量的影响。 3. **内层循环** 内层循环从大到小遍历背包容量 \( j \),这样可以防止重复利用同一个物品多次。 4. **更新状态** 对于每个物品 \( i \),如果它的重量小于等于当前背包容量 \( j \),则尝试更新 `dp[j]` 的值。 #### 示例代码 以下是一个完整的 Java 实现示例: ```java public class Knapsack { public static void main(String[] args) { int[] weight = {1, 3, 4}; int[] value = {15, 20, 30}; int bagsize = 4; // 初始化 dp 数组 int[] dp = new int[bagsize + 1]; // 遍历每个物品 for (int i = 0; i < weight.length; i++) { // 倒序遍历背包容量 for (int j = bagsize; j >= weight[i]; j--) { dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]); } } // 输出最终结果 System.out.println("最大价值:" + dp[bagsize]); // 打印整个 dp 数组 for (int j = 0; j <= bagsize; j++) { System.out.print(dp[j] + " "); } } } ``` #### 结果解释 上述代码中的 `dp[bagsize]` 即为所求的最大价值。程序运行结束后,可以通过打印 `dp` 数组查看各个容量对应的最优解。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值