关于物品大小较小的01背包
关于物品大小较小的01背包
设题目给出的物品大小为 \(w_i\),个数为 \(n\) ,总和为 \(N\)。
前言
这个东西可能纯粹是乱搞。
发现 WC2020 选课这个题直接被一个错误的写法爆水。
ps: 这个题是大小范围 1~3 ,实际上正解复杂度很高。
\(w_i\in\{1,2\}\)
这个范围的 01背包,实际上可以:
回撤贪心,从小到大考虑,每次要让总和加一,则决策就是 选一个 1 或者 选一个 2,删掉一个 1
奇怪的dp? (先放着下面讲)
\(w_i\in\{1,2,3\}\)
好像是并没有很好的写法的,在 WC2020选课 这道题中,由于求出的背包只需要访问最后 \(L\) 个结果。
配合上面的贪心,先求出 \(w_i\in\{1,2\}\) 的,然后和 3的暴力合并求出 \(L\) 个位置的结果,复杂度为 \(O(NL)\)。
作为乱搞选手,然后想要提一下这个奇怪的dp,
大概可以表达为:
对于每种权值的物品分别排序,
每个dp位置记录答案的同时,记录方案在每种权值里选择了几个,
转移就是考虑每种权值选择剩下的最优的一个。
实际上,这个 dp 在 \(w_i\leq 2\) 时正确性显然,实际原理是与贪心一致的。
而当 \(w_i\leq 3\) 时,由于转移不完全,在实际随机数据测试中发现:
(ps:由于比较难搞暴力,所以只有测试\(n\leq 1000\)的)
可能存在一个位置的dp值没有被转移到
可能存在若干个位置(约 0~1/60 的比率,大部分情况都在 1/200 以下)的 dp值错误
3.这个错误率在权值值域越小时错误率越低,在值域为10时几乎不会错(雾)
这似乎可以解释为什么WC出题人没有卡掉这个错误的dp,因为真的比较难卡?
然后尝试了几种乱搞性质的优化,发现
- 每次多枚举几个物品。
效果不佳。
- 记录前 \(k\) 大不同的 dp 值(实际上,是指通过比较决策是否相同来判断 dp 值是否相同)。
当 \(w_i\leq 3\) 时,\(k\) 达到 3后几乎不可能错(近万组没锅)。
当 \(w_i\leq 4\) 时,\(k\) 达到6后几乎不可能错 (实际还是出现过错误,要想完全正确比较难,但是如果调整到 \(k=11\) 时上千组可能才会有一个位置不一样)。
测试了 \(w_i\leq 7\) 左右的情况。
发现想要完全正确很难,但是调整 \(k\) 的大小后,总是可以让正确率非常高(然而这个 \(k\) 可能比较大,甚至需要记录几十个)。
并且发现出现错误的位置几乎只有没有被dp到的那一个位置。
- 正反dp!
沿用上面的 前 k 大优化,调整参数。
正反 dp 就是再求一次不选 \(i\) 个时最小的花费。
然后两边取 max。
这个优化可以大幅提高正确率。
\(w=3,k=1\) 几乎不会错。
\(w=4,k=1\) 时上万组错一个,\(k=2\) 几乎不会错。
\(w=5,k=2\) 几乎不会错。
\(w=6,k=2\) 5000 组错一个,\(k=3\) 几乎不会错
参数调一下就可以了,不知道上界是多少,测了 \(w=10,k=10\) 看起来问题不大
附一下评测的代码,希望这个问题能够得到神仙的完美解决!
数据生成器
1 |
|
优化2:
1 |
|
优化3:
1 |
|