咨询:带类别必选约束的背包问题对应何种已知变体及实现方案?
问题对应的背包变体及解决方案
你遇到的这个问题是分组背包问题(Group Knapsack Problem)的约束强化版——普通分组背包允许每个类别(组)选择0个或1个物品,但你的场景要求每个类别必须恰好选择一个物品,我们可以称它为「强制选择型分组背包问题」。
核心解法思路
这类问题最适合用动态规划(DP)解决,核心逻辑是在普通分组背包的基础上调整状态转移规则:
- 定义DP状态:
dp[i][w]表示考虑前i个类别,总重量不超过w时能获得的最大收益;用负无穷标记「不可行状态」(比如前i个类别无法凑出总重量w的情况)。 - 初始化状态:第一个类别必须选一个物品,所以遍历第一个类别的所有物品,将重量≤
Wmax的物品对应的dp[1][wj]设为该物品的收益。 - 状态转移:对于第
i个类别的每个物品(重量wj,收益pj),遍历所有可能的重量w,如果dp[i-1][w - wj]是可行状态(非负无穷),则更新dp[i][w] = max(dp[i][w], dp[i-1][w - wj] + pj)。 - 结果提取:
dp[总类别数][Wmax]就是满足条件的最大收益,还可以通过回溯DP数组找到具体选中的物品。
代码实现(Python)
我们用你给出的示例来验证代码逻辑:
def forced_group_knapsack(Wmax, groups): num_groups = len(groups) # 初始化DP数组,负无穷代表该状态不可行 dp = [[-float('inf')] * (Wmax + 1) for _ in range(num_groups + 1)] # 处理第一个分组:必须选一个物品 first_group = groups[0] for wj, pj in first_group: if wj <= Wmax: dp[1][wj] = max(dp[1][wj], pj) # 处理后续分组 for i in range(2, num_groups + 1): current_group = groups[i-1] # 遍历所有可能的重量状态 for w in range(Wmax + 1): # 只有上一组的状态可行时,才能基于它更新当前组 if dp[i-1][w] != -float('inf'): for wj, pj in current_group: if w + wj <= Wmax: if dp[i][w + wj] < dp[i-1][w] + pj: dp[i][w + wj] = dp[i-1][w] + pj # 找到最大收益 max_profit = max(dp[num_groups]) # 回溯选中的物品(可选步骤) selected_items = [] current_weight = Wmax for i in range(num_groups, 0, -1): current_group = groups[i-1] for wj, pj in current_group: if current_weight >= wj and dp[i][current_weight] == dp[i-1][current_weight - wj] + pj: selected_items.append((wj, pj)) current_weight -= wj break selected_items.reverse() return max_profit, selected_items # 示例输入 Wmax = 400 # 每个子列表代表一个类别,元素为(重量, 收益) groups = [ [(500, 25), (150, 5)], # 书籍类:《圣经》《小王子》 [(80, 120), (250, 200)] # 食品类:奶酪、香蕉 ] max_p, selected = forced_group_knapsack(Wmax, groups) print(f"最大收益:{max_p}") print(f"选中物品(重量,收益):{selected}")
运行后会输出:
最大收益:205 选中物品(重量,收益):[(150, 5), (250, 200)]
完全匹配你示例中的最优解:《小王子》(150,5)+香蕉(250,200),总重量刚好400,总收益205。
额外提示
- 如果某个类别中所有物品的重量都超过剩余背包容量,该状态会保持负无穷,代表无解,需要提前判断输入合法性。
- 空间优化:可以把二维DP数组压缩成一维,从后往前遍历重量,避免覆盖未使用的状态,逻辑和普通分组背包类似,但要严格遵守「必须选当前组物品」的约束。
内容的提问来源于stack exchange,提问作者Cornélius Cellier
相关产品推荐
相关产品推荐

