特殊的背包问题

特殊的背包问题

\(n\) 为物品个数,\(m\) 为背包容量,\(k\) 为所有物品中重量最大值。

1. 最优化问题

\(m\) 较大时可以应用下面的解法。先贪心,然后扔掉一些,再补上一些。

1.1 完全背包 1

先找出性价比最高的物品,一直填这个物品,直到将要溢出。设这个物品的重量为 \(x\)

其他物品最多选择 \(x-1\) 个。若选择了 \(x\) 个,根据鸽巢原理,一定有一段的重量和是 \(x\) 的倍数,否则换成性价比最高的物品一定不劣,于是背包容量只需要开到 \(k^2\)

而重量相同的物品只需要保留价值最大的,所以复杂度 \(O(n+k^3)\)

1.2 完全背包 2

当保证 \(m>k^2\) 时,有 \(O(nk)\) 的同余最短路做法。

P9140 [THUPC 2023 初赛] 背包 做题记录 - XP3301_Pipi - 博客园 (cnblogs.com)

1.3 完全背包 3

对于一个物品集合,一定存在一种划分方式,使得两部分的重量和之差 \(\le k\)

所以,我们可以将 \(m\) 分解为 \((\frac m 2-i)+(\frac m 2+i)\),其中 \(0\le i\le \frac k 2\),分成两个独立子问题。

区间初始为 \([m,m]\),变为 \([\frac{m-k} 2,\frac{m+k} 2]\),再变为 \([\frac{m-3k} 4,\frac{m+3k}4]\),一直向下。

考虑 \(k\) 前系数,\(f_0=0,f_i=\frac{f_{i-1}+1}{2}\),不难得到 \(f_i=1-2^{-i}\)。所以区间长度不超过 \(2k\)

向下递归,直到 \(m\le 2k\),这部分预处理即可。复杂度 \(O(nk+k^2\log m)\)

1.4 多重背包

将所有物品按性价比从大到小排序,先贪心从前向后选择,直到将要溢出。

将重量为相同的物品分成一类,若该类物品已经被选择 \(p\) 个,那么最终至多扔掉 \(k-1\) 个。

设重量为 \(x\) 的物品被扔掉了 \(k\) 个。那么在后面补上来的物品中,价值和与重量和一定比扔掉的这些大,否则与贪心过程矛盾,于是补上来的物品至少有 \(x\) 个。在这 \(x\) 个物品中,一定有一段的重量和是 \(x\) 的倍数,把这段物品换成被扔掉的一定不劣。于是背包容量只需要开到 \(k^3\)

每类物品剩下的部分,只需要保留 \(\frac {k^3} p\) 个价值最大的物品。复杂度 \(O(n\log n+k^6\ln k)\)

2. 子集和问题

只需要知道是否存在一个子集使得重量和为 \(m\),无需考虑价值和。

2.1 01 背包 1

朴素 \(O(nm)\),bitset 优化到 \(O(nm/w)\)

2.2 多重背包 1

再设一个 \(g_j\) 表示拼出重量和为 \(j\) 的物品最少需要多少第 \(i\) 类物品,当 \(g_j<c_i\) 时才能向后转移。\(O(nm)\)

2.3 01 背包 2

\(\sum w_i=S\)。将 \(w_i\) 相同的分为一组,最多 \(O(\sqrt{S})\) 个非空组。直接应用 2.2 可以做到 \(O(m\sqrt{S})\)

对每个组进行二进制拆分。设每个组大小为 \(a_i\),则 \(a_i\ge 2^w\) 的个数不会超过 \(O(\sqrt{\frac S {2^w}})\),所以总物品个数不超过 \(O(\sqrt{S})\)。应用 2.1 做到 \(O(m\sqrt{S}/w)\)

2.4 01 背包 3

先从前向后选,直到将要溢出。设选出的物品重量和为 \(S\),则 \(S\ge m-k\)

扔掉左边一些物品,再补上右边一些物品。那么把左边物品的重量取反,问题转化为是否有重量和为 \(m-S\) 的子集。

若存在这样一个子集,将其随机打乱后,其前缀和最大值期望 \(O(k\sqrt{n})\)。证明相当复杂,我不会

那么将数组随机打乱后,背包大小只需要 \(k\sqrt{n}\),应用 2.1 做到 \(O(nk\sqrt{n}/w)\)

2.5 完全背包 2

选择一个物品为基准,以这个物品的重量为模数跑同余最短路,\(O(nk)\)

还可以求出 \([1,m]\) 中有多少能被拼出来。

2.6 多重背包 2

扩展 2.5 的做法。应用转圈技巧和单调队列优化即可。

2.7 01 背包 4

先从前向后选,直到将要溢出,然后进行调整。调整过程中,可以保证重量和始终在 \([m-k,m+k]\) 内:若 \(S<m\) 则补上右边的,若 \(S<m\) 则扔掉左边的,\(S=m\) 时随意。

\(f_{l,r,w}\) 为考虑 \([l,r]\) 中的物品,能否调整到 \(w\),转移枚举是否选择左右端点,复杂度 \(O(n^2k)\)

\(r\) 固定时,\(f_{l,r,w}=1\)\(l\) 一定是一段前缀。更换状态,设 \(f_{r,w }\) 为以 \(r\) 为左端点时,使得调整到 \(w\) 可行的最大的 \(l\)。列出转移:

  • \(f_{r-1,w}\rightarrow f_{r,w}\);
  • \(f_{r-1,w}\rightarrow f_{r,w+a_r}\)
  • \(l\rightarrow f_{r,w-a_l}\)\(l<f_{r,w}\)

直接做仍然是 \(O(n^2k)\) 的,但第三种转移中只需要考虑 \(f_{r-1,w}\le l<f_{r,w}\)\(l\),因为其他 \(l\)\(f_{r-1,w}\) 处讨论过了,然后经过第一种转移到了 \(f_{r,*}\)。这样就做到 \(O(nk)\) 了。

posted @ 2025-10-26 18:48  XP3301_Pipi  阅读(6)  评论(0)    收藏  举报
Title