You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多背包总价值优化:如何处理物品隔箱恢复价值的决策?

解决多背包DP中跳过箱子恢复物品全值的优化问题

问题描述

商店有N个可放置瓶子的箱子(允许空箱),每个箱子有两个属性:

  • 奖励系数 c_i
  • 承重上限 l_i

规则细节:

  1. 共有K个瓶子,每个瓶子包含:
    • 基础分值 p_j(支持负数)
    • 放置所需重量 t_j
  2. 每个瓶子在单个箱子中最多放1次,且不可拆分
  3. 瓶子分值计算规则:
    • 若连续两个箱子都放置了该瓶子,当前箱子中该瓶子的分值为 ⌊p_j/2⌋
    • 若中间跳过至少一个箱子未放置该瓶子,再次放置时恢复全值 p_j
  4. 单箱得分公式:(箱内所有瓶子分值总和) × c_i × 箱内瓶子数量

输入输出格式

输入

  • 首行:两个整数N(箱子数)、K(瓶子数)
  • 接下来N行:每行两个整数 c_i、l_i,对应第i个箱子的奖励系数和承重
  • 最后K行:每行两个整数 p_j、t_j,对应第j个瓶子的基础分值和重量

输出

  • 首行:最大总得分T
  • 后续N行:每行输出对应箱子的放置情况(即放置的瓶子编号列表,空箱则输出空行或按题目要求的格式)

现有代码的核心缺陷

当前基于多背包的DP实现未覆盖跳过箱子以让后续瓶子恢复全值的场景。比如部分测试用例中,跳过某个箱子后,后续放置的瓶子能以全值计算,总得分会显著提升,但现有代码无法捕捉这种最优决策。

解决方案思路

要解决这个问题,必须在DP状态中加入瓶子冷却状态的维度,跟踪每个瓶子上一次放置的间隔情况,具体设计如下:

1. 状态定义

设计dp[i][state],其中:

  • i:当前处理到第i个箱子(从1到N)
  • state:一个长度为K的二进制状态数组(或整数掩码,当K≤20时),每个位标记对应瓶子的冷却状态:
    • 0:上一个箱子未放置该瓶子,当前放置可使用全值p_j
    • 1:上一个箱子放置了该瓶子,当前放置只能使用半值⌊p_j/2⌋
  • 每个状态存储两个信息:当前累计的最大总得分,以及前驱状态和当前箱子的物品选择(用于回溯输出)

2. 状态转移

对于每个箱子i,有两种核心决策:

决策1:跳过当前箱子

此时所有瓶子的冷却状态重置为0(因为间隔了一个箱子,下次放置可恢复全值)。状态转移为:

dp[i+1][all_0_state] = max(dp[i+1][all_0_state], dp[i][current_state].score)

同时记录前驱状态为current_state,当前箱子无物品放置。

决策2:在当前箱子放置物品

基于当前状态current_state,对第i个箱子做一次0-1背包计算:

  • 选择一组总重量≤l_i的瓶子子集
  • 对每个选中的瓶子j,根据current_state[j]计算得分:current_state[j] == 0 ? p_j : floor(p_j/2)
  • 计算当前箱子的得分:(选中瓶子分值总和) × c_i × 选中瓶子数量
  • 生成新状态new_state:选中的瓶子标记为1(下一个箱子若再放则用半值),未选中的标记为0
  • 状态转移为:
new_total_score = dp[i][current_state].score + 当前箱子得分
if new_total_score > dp[i+1][new_state].score:
    dp[i+1][new_state].score = new_total_score
    dp[i+1][new_state].prev_state = current_state
    dp[i+1][new_state].selected_bottles = 本次选中的瓶子列表

3. 优化策略

  • 滚动数组压缩空间:由于第i+1个箱子的状态仅依赖第i个箱子的状态,只需维护两个状态集合(当前轮、下一轮)即可,无需存储所有N轮的状态。
  • 剪枝无效状态:对于得分低于当前同状态最优值的状态直接丢弃,减少计算量。
  • 负数分值处理:在背包选择时,若某个瓶子的当前计算分值为负,且加入后会降低箱子得分,则直接跳过该瓶子。

4. 路径回溯

从N+1轮的最优状态(所有状态中得分最高的)开始,反向回溯每个箱子的决策:

  • 若当前状态的前驱是跳过箱子的状态,则对应箱子为空
  • 若前驱是放置物品的状态,则取出记录的选中瓶子列表,作为该箱子的放置情况
  • 逐步回溯到第1个箱子,最后反转得到从第1到第N个箱子的放置序列

实现注意事项

  • 当K较大(如超过20),二进制掩码无法直接使用,可改用哈希表存储有效状态(仅保留每个冷却状态的最优得分),避免状态爆炸。
  • 背包计算时,可采用常规0-1背包的一维数组优化,提升计算效率。
  • 注意整数除法的向下取整实现(如在Python中用p_j // 2,需处理负数情况,例如-3//2为-2,符合⌊-3/2⌋的要求)。

内容的提问来源于stack exchange,提问作者HelloContinent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 08:52:34