背包九讲(二)——完全背包问题
参考了著名的背包九讲,可以在这里下载,绪前一篇的01背包问题
1.1 问题
有N
种物品和一个容量为V
的背包,每种物品都有无限件可用,放入第i
件物品的费用是$C_i$,得到的价值是$W_i$。求解将哪些物品装入背包可使价值综合最大。
1.2 解题思路
完全背包和01背包唯一的区别就在于一件物品是否能多次选择?
知道这个区别,其实仔细一想,就能完全背包问题转化为01背包,因为容量V是有限的,对于单个物品$C_i$来说,最多只能放如$\left \lfloor V/C_i\right \rfloor$件,所以我们只需要将完全背包问题看成是有$\left \lfloor V/C_1\right \rfloor$件物品$C_1$、有$\left \lfloor V/C_2\right \rfloor$件物品$C_2$、…、$\left \lfloor V/C_N\right \rfloor$件物品$C_N$的01背包问题就可以了。但是此时总的复杂度可以认为是$O(NV\sum \cfrac{V}{C_i})$,这个复杂度有点高了~
更进一步,我们其实有更加高效的转化方法,用二进制的思想,我们可以将第 i 种物品拆解为费用为$C_i2^K$,价值为$W_i2^k$的若干件物品,其中k取1至$C_i2^k \le V$的最大整数(其实k可以取所有i种物品费用和小于V的整数),然后时间复杂度就可以优化为$O(NVlog(\left \lfloor V/C_2\right \rfloor))$了。相比之前低了不少~
当然,最nb的解法都不是上面说的hhh,在求解01背包问题时需要要求 $v$ 按照递减的顺序从 $V,V-1,..,0$ 计算 $dp[v]$ ,让 v 递减计算是为了保证状态$dp[v]$是由上一轮递推而来的,其实也就是保证一件物品只被选择一次,但是现在允许选择多次了,岂不美哉~ 非常简单,让 v 递增计算dp[v]即可,请参考下面伪代码:
1 | dp[0...V] ← 0 |
所以此时问题的时间复杂度已经降到了$O(NV)$了,秒啊~
但是完全背包就不存在01背包里的那个常数优化了~
一个简单有效的优化,若两件物品 i,j 满足$C_i \lt C_j$并且$W_i \ge W_j$,那么可以直接将物品 j 直接去掉,这个过程可以在$O(N^2)$的时间复杂度内实现,并不是很高,如果被卡时间了,可以试试这个简单的优化~
1.3 示例代码
懒得写了~还得自己造数据,和01背包问题代码类似的
1.4 实战阶段
做几道题就清楚辣!!
题目描述:
LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是 LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
每种草药可以无限制地疯狂采摘。
药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!
具体输入输出格式以及样例请参考原题网站~
这就是一个典型的完全背包问题,直接按照上面的思路写就可以,但是这题的数据量是比较大的,注意dp数组使用long long
类型,以及动态生成数组防止内存爆炸,还有就是STL是在太慢了~用malloc吧~
1 |
|
提交结果:
如果使用STL。。。。
STL是malloc的两倍了~当然这里不卡时间没有啥影响