牛客题解 | 04.02_完全背包

完全背包

问题描述

n n n 个物品,每个物品有重量 w i w_i wi 和价值 v i v_i vi。现在有一个容量为 W W W 的背包,每个物品可以选择任意次(无限次),求解在不超过背包容量的情况下,能够装入物品的最大价值。

与01背包的区别

  1. 01背包:每个物品最多选择一次
  2. 完全背包:每个物品可以选择无限次

动态规划解法

状态定义

  • 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][j-w[i]] + v[i])  if j >= w[i]
dp[i][j] = dp[i-1][j]                              if j < w[i]

注意:与01背包的区别是 d p [ i ] [ j − w [ i ] ] dp[i][j-w[i]] dp[i][jw[i]] 而不是 d p [ i − 1 ] [ j − w [ i ] ] dp[i-1][j-w[i]] dp[i1][jw[i]]

代码实现

C++ 实现(二维)

int completeKnapsack(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][j-w[i-1]] + v[i-1]);
            } else {
                dp[i][j] = dp[i-1][j];
            }
        }
    }
    
    return dp[n][W];
}

C++ 实现(一维优化)

int completeKnapsack(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[i]; j <= W; j++) {
            dp[j] = max(dp[j], dp[j-w[i]] + v[i]);
        }
    }
    
    return dp[W];
}

Java 实现

class Solution {
    public int completeKnapsack(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[i]; j <= W; j++) {
                dp[j] = Math.max(dp[j], dp[j-w[i]] + v[i]);
            }
        }
        
        return dp[W];
    }
}

Python 实现

def completeKnapsack(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[i], W + 1):
            dp[j] = max(dp[j], dp[j-w[i]] + v[i])
    
    return dp[W]

与01背包的代码区别

  1. 状态转移时使用当前行的状态
  2. 容量的遍历方向改为正序
  3. 可以直接从物品重量开始遍历

时间复杂度分析

  • 时间复杂度: 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. 求满足条件的最小代价

应用场景

  1. 零钱兑换问题
  2. 物资补给规划
  3. 资源重复利用
  4. 生产计划制定
  5. 库存补货策略

注意事项

  1. 遍历顺序的区别
  2. 状态转移的依赖关系
  3. 初始化的处理
  4. 特殊情况的考虑
  5. 数据范围的限制

经典例题

  1. 【模板】完全背包
  2. 最少的完全平方数
  3. 兑换零钱
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值