牛客题解 | 04.01_01背包

01背包

问题描述

n n n 个物品,每个物品有重量 w i w_i wi 和价值 v i v_i vi。现在有一个容量为 W W W 的背包,每个物品要么选要么不选(0-1),求解在不超过背包容量的情况下,能够装入物品的最大价值。

动态规划解法

状态定义

  • d p [ i ] [ j ] dp[i][j] dp[i][j] 表示考虑前 i i i 个物品,背包容量为 j j j 时能获得的最大价值

状态转移方程

dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])  if j >= w[i]
dp[i][j] = dp[i-1][j]                                if j < w[i]

初始状态

  • d p [ 0 ] [ j ] = 0 dp[0][j] = 0 dp[0][j]=0 表示不选任何物品时的价值为0
  • d p [ i ] [ 0 ] = 0 dp[i][0] = 0 dp[i][0]=0 表示背包容量为0时的价值为0

代码实现

C++ 实现(二维)

int knapsack(vector<int>& w, vector<int>& v, int W) {
    int n = w.size();
    vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));
    
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= W; j++) {
            if (j >= w[i-1]) {
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]] + v[i-1]);
            } else {
                dp[i][j] = dp[i-1][j];
            }
        }
    }
    
    return dp[n][W];
}

C++ 实现(一维优化)

int knapsack(vector<int>& w, vector<int>& v, int W) {
    int n = w.size();
    vector<int> dp(W + 1, 0);
    
    for (int i = 0; i < n; i++) {
        for (int j = W; j >= w[i]; j--) {
            dp[j] = max(dp[j], dp[j-w[i]] + v[i]);
        }
    }
    
    return dp[W];
}

Java 实现

class Solution {
    public int knapsack(int[] w, int[] v, int W) {
        int n = w.length;
        int[] dp = new int[W + 1];
        
        for (int i = 0; i < n; i++) {
            for (int j = W; j >= w[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j-w[i]] + v[i]);
            }
        }
        
        return dp[W];
    }
}

Python 实现

def knapsack(w: List[int], v: List[int], W: int) -> int:
    n = len(w)
    dp = [0] * (W + 1)
    
    for i in range(n):
        for j in range(W, w[i]-1, -1):
            dp[j] = max(dp[j], dp[j-w[i]] + v[i])
    
    return dp[W]

空间优化

  1. 二维转一维:

    • 观察到当前状态只依赖于上一行的状态
    • 可以用一维数组滚动更新
    • 必须逆序遍历容量,防止状态被覆盖
  2. 初始化优化:

    • 一维数组只需要初始化一次
    • 所有位置初始化为0即可

时间复杂度分析

  • 时间复杂度: O ( n ⋅ W ) \mathcal{O}(n \cdot W) O(nW)
  • 空间复杂度:
    • 二维实现: O ( n ⋅ W ) \mathcal{O}(n \cdot W) O(nW)
    • 一维实现: O ( W ) \mathcal{O}(W) O(W)

变体问题

  1. 完全背包:每个物品可以选无限次
  2. 多重背包:每个物品有特定的数量限制
  3. 分组背包:物品分组,每组最多选一个
  4. 二维费用背包:物品有两种限制条件
  5. 依赖背包:物品之间有依赖关系

应用场景

  1. 资源分配问题
  2. 投资组合优化
  3. 任务调度问题
  4. 物流配送规划
  5. 切割问题优化

注意事项

  1. 数组大小的分配
  2. 边界条件的处理
  3. 逆序遍历的必要性
  4. 状态转移的正确性
  5. 初始化的合理性

经典例题

  1. 【模板】01背包
  2. 装箱问题
  3. 小红取数
  4. 分割等和子集
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值