背包问题

nn 种物品,物品 jj 的重量和价值分别为 wjw_jvjv_j ,如果背包的最大容量限制是 mm ,怎么样选择放入背包的物品以使得背包的总价值最大?

组合优化问题,设 xjx_j 表示装入背包的第 jj 个物品的数量,解可以表示为 <x1,x2,,xn><x_1,x_2,\ldots,x_n> 。那么目标函数和约束条件是:

如果组合优化问题的目标函数和约束条件都是线性函数,称为线性规划。如果线性规划问题的变量 xjx_j 都是非负整数,则称为整数规划问题。背包问题就是整数规划问题。限制所有的 xj=0orxj=1x_j = 0 or x_j = 1 时称为0-1背包。

✏️ 1、0-1背包【链接

n件物品和容量为m的背包,给出每件物品的重量 wiw_i 以及价值 viv_i ,求解让装入背包的物品重量不超过背包容量,且价值最大 。特点:每个物品只有一件供你选择放还是不放。

二维解法:设 f[i][j]f[i][j] 表示前 ii 件物品 总重量不超过 jj 的最大价值,可得出状态转移方程:

f[i][j]=max{f[i1][jw[i]]+v[i], f[i1][j]}f[i][j]=max\{f[i-1][j-w[i]]+v[i],\ f[i-1][j]\}

一维解法:设 f[j]f[j] 表示重量不超过 jj 公斤的最大价值,可得出状态转移方程:

f[j]=max{f[j], f[jw[i]]+v[i]}f[j]=max\{f[j],\ f[j−w[i]]+v[i]\}

✏️ 2、完全背包【链接

nn 件物品和容量为 mm 的背包,给出每件物品的重量 wiw_i 以及价值 viv_i ,求解让装入背包的物品重量不超过背包容量,且价值最大 。特点:每个物品可以无限选用

一维解法: 设 f[j]f[j] 表示重量不超过 jj 公斤的最大价值,可得出状态转移方程:

f[j]=max{f[j], f[jw[i]]+v[i]}f[j]=max\{f[j],\ f[j−w[i]]+v[i]\}

✏️ 3、多重背包链接(京东笔试)

nn 件物品和容量为 mm 的背包。给出每件物品的数量 sis_i 、重量 wiw_i 以及价值 viv_i ,求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。特点: 每个物品都有了一定的数量

二维解法:把 sis_i 个物品逐个拆分,则得到 si\sum s_i 个物品,原问题转化为01背包问题,时间复杂度为 O(m×si)O(m\times \sum s_i) 。也可以在转移得过程中枚举 kk ,代表第 ii 个物品选取的数量,则转移方程为:

f[i][j]=max0ks[i]{f[i1][jk×v[i]]+k×w[i]}f[i][j]=\mathop{max}\limits_{0\le k \le s[i]}\{f[i - 1][j - k\times v[i]] + k\times w[i]\}

一维解法:设 f[j]f[j] 表示重量不超过 jj 公斤的最大价值,可得出状态转移方程:

f[j]=max0ks[i]{f[jk×w[i]]+k×v[i]}f[j] = \mathop{max}\limits_{0\le k \le s[i]}\{f[j−k\times w[i]]+k\times v[i]\}

优化:

1、二进制优化

将第 ii 种物品分成若干件物品,可以有 (vi,wi),(vi×2,wi×2),(vi×4,wi×4)(v_i,w_i),(v_i\times 2,w_i\times 2),(v_i\times 4,w_i\times 4)\ldots 等等,每件物品有一个系数,分别为 1,2,4,,2k1,n2k+11,2,4,\ldots,2^{k - 1},n-2^k+1kk 是满足的最大整数。例如, nn 为13,拆分成 1,2,4,61,2,4,6 四件物品,根据二进制的性质, 0130\ldots 13 都可以由这四件物品组合得到。于是, nn 件物品,就拆分成至多 lognlogn 件物品。再转化为01背包问题求解,复杂度降至 O(m×logn)O(m\times \sum logn)

2、单调队列优化

将背包的容量按照的剩余分成组:

仔细观察转移方程,会发现真正的转移只会发生在同一组内,不同的组是不可能转移的可以改一下上面的转移方程:

f[b+x×v[i]]=max0ks[i]{f[b+(xk)×v[i]]+k×w[i]}f[b+x\times v[i]] = \mathop{max}\limits_{0\le k \le s[i]}\{f[b+(x-k)\times v[i]]+k\times w[i]\}

t=xkt = x - k ,状态转移方程变成:

f[b+x×v[i]]=maxxs[i]tx{f[b+t×v[i]]t×w[i]}+x×w[i]f[b+x\times v[i]] = \mathop{max}\limits_{x-s[i]\le t \le x}\{f[b+t\times v[i]]-t\times w[i]\} + x\times w[i]

这里的转移实际上一对 (b,x)(b,x) 唯一对应一个 jj 。我们固定 bb ,那么对于 xx 的决策 tt 的集合正好是一个滑动区间,而 maxmax 里面是一个和 xx 无关的式子,所以可以用单调队列来维护。具体算法如下:

  • 枚举一个 iib(0bv[i])b(0\le b\le v[i])

  • 从小到大枚举 xx ,并且用单调队列来维护 f[b+t×v[i]]t×w[i]f[b+t\times v[i]]-t\times w[i] 关于 tt 单调下降,更新 f[b+x×v[i]]f[b+x\times v[i]] 的值。

由于每个剩余类最多只有 mv[i]\frac{m}{v[i]} 个元素,那么对于一个 ii ,转移的总时间为 O(mv[i]×v[i])=O(m)O(\frac{m}{v[i]} \times v[i]) = O(m) ,所以算法的时间复杂度为 O(n×m)O(n\times m) ,这样我们就又优化掉了多重背包中的物品个数这一维。

最后更新于

这有帮助吗?