java 01背包问题(滚动数组优化)

本文详细解析了二维动态规划在01背包问题中的应用,介绍了状态转移方程,并展示了如何通过一维数组优化降低空间复杂度。还提供了Java代码示例,演示了解决该问题的过程。
摘要由CSDN通过智能技术生成

1. 二维DP解法分析

在01背包问题中,我们有一组物品,每个物品有自己的重量和价值,我们需要选择一些物品放入背包中,使得背包的总重量不超过背包容量,且价值最大化。

首先,我们定义一个二维数组 dp[i][j],其中 dp[i][j] 表示在考虑前 i 个物品,且背包容量为 j 的情况下,背包中所能装下的最大价值。

状态转移方程为:

dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i])

其中,weight[i] 表示第 i 个物品的重量,value[i] 表示第 i 个物品的价值。

物品\容量012345678
无物品000000000
物品1022222222
物品1,2022577777
物品1,2,302257781010

2. 一维DP优化

在上述二维DP解法中,我们可以观察到在计算 dp[i][j] 时,只依赖于 dp[i-1][j]dp[i-1][j-weight[i]],即只依赖于上一行的结果。因此,我们可以将二维数组优化为一维数组,仅保留一行的信息。
状态转移方程为:

dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);
//相当于直接在二维数组的上一层倒序更新,看看这个容量的背包是保持当前的值最大 还是加入物品后的价值更大
  • 二维DP解法的时间复杂度:O(n * capacity),其中 n 是物品的数量,capacity 是背包的容量。空间复杂度为 O(n * capacity)
  • 一维DP优化后的时间复杂度:O(n * capacity),空间复杂度为== O(capacity)==。

通过将二维数组优化为一维数组,我们降低了空间复杂度。

3. 步骤演示

物品背包容量012345678
初始000000000

物品1:

  • 当背包容量为0时,无法放入物品1,保持为0。
  • 当背包容量为8时,放入物品1,dp[8] = 2。
  • 当背包容量为7时,放入物品1,dp[7] = 2。
  • 当背包容量为6时,放入物品1,dp[6] = 2。
  • 当背包容量为5时,放入物品1,dp[5] = 2。
  • 当背包容量为4时,放入物品1,dp[4] = 2。
  • 当背包容量为3时,放入物品1,dp[3] = 2。
  • 当背包容量为2时,放入物品1,dp[2] = 2。
  • 当背包容量为1时,放入物品1,dp[1] = 2。
物品背包容量012345678
物品1022222222

物品2:

  • 当背包容量为8时,放入物品2,dp[8] = max(dp[8], dp[8 - 3] + 5) = max(2 , 2+5)= 7。
  • 当背包容量为7时,放入物品2,dp[7] = max(dp[7], dp[7 - 3] + 5) = max(2 , 2+5) = 7。
  • 当背包容量为6时,放入物品2,dp[6] = max(dp[6], dp[6 - 3] + 5) = max(2 , 2+5) = 7。
  • 当背包容量为5时,放入物品2,dp[5] = max(dp[5], dp[5 - 3] + 5) = max(2 , 2+5) = 7。
  • 当背包容量为4时,放入物品2,dp[4] = max(dp[4], dp[4 - 3] + 5) = max(2 , 2+5) = 7。
  • 当背包容量为3时,放入物品2,dp[3] = max(dp[3], dp[3 - 3] + 5) = max(2 , 0+5) = 5。
  • 当背包容量为2时,无法放入物品2,保持为2。
  • 当背包容量为1时,无法放入物品2,保持为2。
  • 当背包容量为0时,无法放入物品2,保持为0。
物品背包容量012345678
物品2022577777

物品3:

  • 当背包容量为8时,放入物品3,dp[8] = max(dp[8], dp[8 - 6] + 8) = max(7, 2 + 8) = 10。
  • 当背包容量为7时,放入物品3,dp[7] = max(dp[7], dp[7 - 6] + 8) = max(7, 2 + 8) = 10。
  • 当背包容量为6时,放入物品3,dp[6] = max(dp[6], dp[6 - 6] + 8) = max(7, 0 + 8) = 8。
  • 当背包容量为5时,无法放入物品3,保持为7。
  • 当背包容量为4时,无法放入物品3,保持为7。
  • 当背包容量为3时,无法放入物品3,保持为5。
  • 当背包容量为2时,无法放入物品3,保持为2。
  • 当背包容量为1时,无法放入物品3,保持为2。
  • 当背包容量为0时,无法放入物品3,保持为0。
物品背包容量012345678
物品302257781010

演算解释:

  1. 在放入物品1时,背包容量从8到0的状态转移过程中,每次更新dp数组。
  2. 继续放入物品2时,同样地,背包容量从8到0的状态转移过程中,每次更新dp数组。
  3. 最后放入物品3时,背包容量从8到0的状态转移过程中,每次更新dp数组。

注意要逆序更新,保证每个物品只使用一次

4. Java代码实现

下面是用Java实现的01背包问题的滚动数组优化解法:

public class Main {
    // 定义一个方法,用于解决01背包问题
    public static int knapsack(int[] weights, int[] values, int capacity) {
        // 获取物品数量
        int n = weights.length;
        // 创建一维数组,用于保存背包容量对应的最大价值
        int[] dp = new int[capacity + 1];//!!/数组大小定义记得是容量+1 !!

        // 遍历每个物品
        for (int i = 0; i < n; i++) {
            // 逆序遍历背包容量,确保不重复选择同一物品
            /*这里判断条件的含义是遍历到的当前背包容量至少要大于等于当前遍历到的物品的容量才判断装或者不装,
            不然都装不下,没必要判断,退出循环即可*/
            for (int j = capacity; j >= weights[i]; j--) {//不要漏等于号!!!是可以装满背包的!!!
                // 使用状态转移方程更新当前背包容量的最大价值
                dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);
            }
        }

        // 返回背包容量为capacity时的最大价值
        return dp[capacity];
    }

    public static void main(String[] args) {
        // 给定物品的重量和价值,以及背包的容量
        int[] weights = {1, 3, 6};
        int[] values = {2, 5, 8};
        int capacity = 8;

        // 调用knapsack方法计算最大价值
        int max_value = knapsack(weights, values, capacity);
        // 输出结果
        System.out.println("可以获得的最大价值:" + max_value);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BenChuat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值