更快的完全背包算法
考虑这样一个问题:我们有一个完全背包(每个物品有无限个),有 n 种物品,每个物品有两个属性 w,c,w(w<=n)表示重量,c表示权重,你要求大小恰好为 V 的背包的最大可能权重。
首先考虑这个问题的两个弱化:
https://www.luogu.com.cn/problem/P2371 这个实质上只关心可达性,所以我们背包可以记录在同余类最早什么时候可以到。
https://loj.ac/p/6872 这个由于保证了背包足够大,所以我们不关心最早什么时候到,只关心相对最大权值。
对于我们的问题,如果背包足够大就是 loj6872,但是不够大(V<=n^2)的情况下我们需要新的算法,下面我将循序渐进地提出一个 O(n^2\log n) 的算法去解决这个问题。
朴素算法是,考虑 dp[i] 表示大小为 i 的答案,我们直接暴力 O(n) 转移这 O(n^2) 个状态,复杂度 O(n^3)。
考虑做一个这样的改良:我们对于前 n 个状态花 O(n) 的代价转移所有物品,后面的第 \(i\) 个状态只转移前 O(n^2/i) 个性价比最高的物品。这样复杂度就是 \(O(n^2log n)\) 了。
(我们不妨假定物品性价比两两不同,相同的可以人为钦定一个顺序)
为了证明这个算法的正确性,我们首先需要证明定理:
在 {1,2,..,n} 中任取 B 个数字,都存在一个首项为 S,公差为 k 的等差序列 p_i = S+ik(i>=0),
满足任意一个 p_i 可以用这 B 个数字的非负线性组合表示出来,且 S<=O(n^2/B),k<=O(n/B),S mod k = 0 (定理 1)
用两个例子感性理解 定理1:
)对于 k 的上界,我们可以通过 n/B,2n/B ... n 这个子集卡到。
)对于 S 的上界,我们可以通过 n,n-1,...n-B+1 这个子集卡到(B远小于n)
等会再说怎么证明,我们考虑如何用这个定理证明这个算法的正确性。
因为考虑任何一个dp方案的物品,我们对它们按照性价比升序排序。
考察一个方案前缀的性质:我们记这个前缀的重量和为 W,性价比最高的元素的性价比是第 B 大,那么我们由这个方案的最优性,这个前缀的任何一个子集都一定不能被性价比前 B-1 大的元素的重量非负线性组合出来,否则我们就找到了一个更优的方案。
我们利用定理 1,找出一个等差数列 S+ik,我们尝试说明 W<=S+nk=O(n^2/B),这样就证明了这个方案可以被我们设计的这个算法 dp 出来。
这个前缀集合中重量 mod k = 0 的元素的重量和一定 <S(否则就不合法),我们让这部分物品必选,然后随意的选择一些物品,直到手上的重量 >=S,剩下的物品重量都 mod k != 0,所以数量一定也小于 k,因为我们考察在 mod k 下后面这些物品的 01 背包,k 个物品就一定可以得到所有同余类,然后就存在一个子集和在这个等差数列中,非法。
我们现在来着手证明定理 1,由于有 B 个元素,我们选出一对 (x,y)(x>=y) 使得 x-y<=n/B,于是 g=gcd(x,y)<=n/B,于是我们在 mod x 下考察。我们建立一个 x 个点的图表示 mod x 下的同余类,然后把 a->(a+y)%x 的边都连出来,这个图一定形成了 g 个环。
我们对元素和环进行抽屉原理,一定存在一个环上有超过 B/g 个元素,而这个环的大小是 n/g。
引理:一个 sum >= 0 的序列,

浙公网安备 33010602011771号