动态规划经典问题解析:混合背包、分组背包与二维费用背包

动态规划经典问题解析:混合背包、分组背包与二维费用背包

LeetCode-Py ⛽️「算法通关手册」:超详细的「算法与数据结构」基础讲解教程,从零基础开始学习算法知识,800+ 道「LeetCode 题目」详细解析,200 道「大厂面试热门题目」。 LeetCode-Py 项目地址: https://gitcode.com/gh_mirrors/le/LeetCode-Py

动态规划是算法设计中非常重要的思想方法,背包问题则是动态规划中最经典的案例之一。本文将深入解析三种常见的背包问题变种:混合背包问题、分组背包问题和二维费用背包问题,帮助读者掌握这些问题的解决思路和实现方法。

混合背包问题解析

混合背包问题是背包问题中最具综合性的变种之一,它融合了0-1背包、完全背包和多重背包三种情况。

问题定义

给定n种物品和一个容量为W的背包,每种物品具有以下特性:

  • 重量weight[i]
  • 价值value[i]
  • 数量count[i]

其中count[i]的不同取值代表不同含义:

  • count[i] = -1:物品只有1件(0-1背包情况)
  • count[i] = 0:物品有无限件(完全背包情况)
  • count[i] > 0:物品有count[i]件(多重背包情况)

解决思路

混合背包问题的核心在于识别每种物品的类型,并采用相应的处理策略:

  1. 二进制优化:首先将所有多重背包物品通过二进制拆分转换为0-1背包物品
  2. 分类处理
    • 对于0-1背包物品,直接保留
    • 对于完全背包物品,标记并保留
  3. 动态规划求解
    • 使用一维dp数组,dp[w]表示容量为w时的最大价值
    • 逆序遍历处理0-1背包物品
    • 正序遍历处理完全背包物品

代码实现

class Solution:
    def mixedPackMethod1(self, weight: [int], value: [int], count: [int], W: int):
        weight_new, value_new, count_new = [], [], []
        
        # 二进制优化处理多重背包
        for i in range(len(weight)):
            cnt = count[i]
            if cnt > 0:  # 多重背包
                k = 1
                while k <= cnt:
                    cnt -= k
                    weight_new.append(weight[i] * k)
                    value_new.append(value[i] * k)
                    count_new.append(1)
                    k *= 2
                if cnt > 0:
                    weight_new.append(weight[i] * cnt)
                    value_new.append(value_new[i] * cnt)
                    count_new.append(1)
            elif cnt == -1:  # 0-1背包
                weight_new.append(weight[i])
                value_new.append(value[i])
                count_new.append(1)
            else:  # 完全背包
                weight_new.append(weight[i])
                value_new.append(value[i])
                count_new.append(0)
                
        dp = [0] * (W + 1)
        
        for i in range(len(weight_new)):
            if count_new[i] == 1:  # 0-1背包
                for w in range(W, weight_new[i] - 1, -1):
                    dp[w] = max(dp[w], dp[w - weight_new[i]] + value_new[i])
            else:  # 完全背包
                for w in range(weight_new[i], W + 1):
                    dp[w] = max(dp[w], dp[w - weight_new[i]] + value_new[i])
                    
        return dp[W]

复杂度分析

  • 时间复杂度:O(W × Σlog₂count[i]),其中W为背包容量
  • 空间复杂度:O(W)

分组背包问题详解

分组背包问题中,物品被分为若干组,每组中的物品相互冲突,最多只能选择一件。

问题定义

给定n组物品和一个容量为W的背包:

  • 第i组有group_count[i]件物品
  • 第i组第j件物品重量为weight[i][j],价值为value[i][j]
  • 每组只能选择最多一件物品

基本解法

二维动态规划

定义dp[i][w]表示前i组物品放入容量为w的背包的最大价值。

状态转移方程:

dp[i][w] = max(dp[i-1][w], dp[i-1][w-weight[i-1][k]] + value[i-1][k])
其中0 ≤ k < group_count[i-1]
优化解法(滚动数组)

使用一维数组优化空间复杂度:

def groupPackMethod2(self, group_count, weight, value, W):
    dp = [0] * (W + 1)
    for i in range(len(group_count)):
        for w in range(W, -1, -1):
            for k in range(group_count[i]):
                if w >= weight[i][k]:
                    dp[w] = max(dp[w], dp[w - weight[i][k]] + value[i][k])
    return dp[W]

复杂度分析

  • 时间复杂度:O(W × Σgroup_count[i])
  • 空间复杂度:O(W)

二维费用背包问题探究

二维费用背包问题在传统背包问题基础上增加了第二维限制条件(如体积)。

问题定义

给定n件物品和一个背包:

  • 每件物品有重量weight[i]和体积volume[i]
  • 背包有重量限制W和体积限制V
  • 每件物品只能选一次

基本解法

三维动态规划

定义dp[i][w][v]表示前i件物品放入重量限制w、体积限制v的背包的最大价值。

状态转移方程:

dp[i][w][v] = max(dp[i-1][w][v], 
                 dp[i-1][w-weight[i-1]][v-volume[i-1]] + value[i-1])
优化解法(二维数组)
def twoDCostPackMethod2(self, weight, volume, value, W, V):
    dp = [[0]*(V+1) for _ in range(W+1)]
    for i in range(len(weight)):
        for w in range(W, weight[i]-1, -1):
            for v in range(V, volume[i]-1, -1):
                dp[w][v] = max(dp[w][v], 
                              dp[w-weight[i]][v-volume[i]] + value[i])
    return dp[W][V]

复杂度分析

  • 时间复杂度:O(n×W×V)
  • 空间复杂度:O(W×V)

总结与比较

这三种背包问题变种各有特点:

  1. 混合背包:综合多种背包类型,需要分类处理
  2. 分组背包:组内物品互斥,增加选择维度
  3. 二维费用:增加限制条件,扩展状态维度

理解这些问题的共性和差异,有助于我们掌握动态规划解决背包类问题的核心思想:定义合适的状态,找到正确的状态转移方程,并根据问题特点进行优化。

LeetCode-Py ⛽️「算法通关手册」:超详细的「算法与数据结构」基础讲解教程,从零基础开始学习算法知识,800+ 道「LeetCode 题目」详细解析,200 道「大厂面试热门题目」。 LeetCode-Py 项目地址: https://gitcode.com/gh_mirrors/le/LeetCode-Py

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

祝珏如

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

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

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

打赏作者

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

抵扣说明:

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

余额充值