牛客题解 | 04.04_分组背包

分组背包

问题描述

nnn 组物品,每组物品有若干个,每组物品中最多只能选择一个。每个物品有重量 wijw_{ij}wij 和价值 vijv_{ij}vij,其中 iii 表示组号,jjj 表示组内编号。现在有一个容量为 WWW 的背包,求解在不超过背包容量的情况下,能够装入物品的最大价值。

与其他背包的区别

  1. 01背包:每个物品最多选择1次
  2. 完全背包:每个物品可以选择无限次
  3. 多重背包:每个物品可以选择有限次
  4. 分组背包:物品分组,每组最多选择1个

动态规划解法

状态定义

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

状态转移方程

dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i][k]] + v[i][k])
其中 k 为第 i 组中的物品编号

代码实现

C++ 实现

int groupKnapsack(vector<vector<int>>& w, vector<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 >= 0; j--) {  // 枚举容量
            for (int k = 0; k < w[i].size(); k++) {  // 枚举组内物品
                if (j >= w[i][k]) {
                    dp[j] = max(dp[j], dp[j-w[i][k]] + v[i][k]);
                }
            }
        }
    }
    
    return dp[W];
}

Java 实现

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

Python 实现

def groupKnapsack(w: List[List[int]], v: List[List[int]], W: int) -> int:
    n = len(w)  # 组数
    dp = [0] * (W + 1)
    
    for i in range(n):  # 枚举每一组
        for j in range(W, -1, -1):  # 枚举容量
            for k in range(len(w[i])):  # 枚举组内物品
                if j >= w[i][k]:
                    dp[j] = max(dp[j], dp[j-w[i][k]] + v[i][k])
    
    return dp[W]

时间复杂度分析

  • 时间复杂度:O(n⋅W⋅k)\mathcal{O}(n \cdot W \cdot k)O(nWk),其中 kkk 是每组物品的平均数量
  • 空间复杂度:O(W)\mathcal{O}(W)O(W)

优化方法

  1. 预处理优化:

    • 预先去除组内被其他物品完全支配的物品
    • 支配关系:重量小价值大的物品支配重量大价值小的物品
  2. 记忆化搜索:

    • 对于组数较少但每组物品较多的情况
    • 可以使用记忆化搜索优化

应用场景

  1. 套装选择问题
  2. 课程选修规划
  3. 技能树培养
  4. 装备搭配优化
  5. 团队人员选择

变体问题

  1. 有依赖的分组背包
  2. 多维费用的分组背包
  3. 有公共物品的分组背包
  4. 求方案数的分组背包

注意事项

  1. 组内物品的处理
  2. 容量的遍历顺序
  3. 状态转移的正确性
  4. 内存使用限制
  5. 特殊情况处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值