分组背包

分组背包

问题描述

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

与其他背包的区别

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

动态规划解法

状态定义

  • 表示考虑前 组物品,背包容量为 时能获得的最大价值

状态转移方程

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]

时间复杂度分析

  • 时间复杂度:,其中 是每组物品的平均数量
  • 空间复杂度:

优化方法

  1. 预处理优化:

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

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

应用场景

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

变体问题

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

注意事项

  1. 组内物品的处理
  2. 容量的遍历顺序
  3. 状态转移的正确性
  4. 内存使用限制
  5. 特殊情况处理
牛客代码笔记-牛栋 文章被收录于专栏

汗牛充栋,学海无涯。<br/> 内含算法知识点讲解,以及牛客题库精选例题。<br/> 学习算法,从牛栋开始。

全部评论
分组背包确实难
点赞 回复 分享
发布于 07-28 23:30 广东

相关推荐

hwwhwh:同双非,有大厂实习其实也没啥用,主要看运气,等就行了
点赞 评论 收藏
分享
10-30 16:31
重庆大学 Java
代码飞升_不回私信人...:你说你善于学习,大家都会说。你说你是985,985会替你表达一切
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务