多重背包O(N*V)算法详解(使用单调队列)(转)
来源:互联网 发布:apache源码包下载 编辑:程序博客网 时间:2024/06/13 07:44
多重背包问题:
有N种物品和容量为V的背包,若第i种物品,容量为v[i],价值为w[i],共有n[i]件。怎样装才能使背包内的物品总价值最大?
网上关于“多重背包”的资料倒是不少,但是关于怎么实现O(N*V)算法的资料,真得好少呀,关于“单调队列”那部分算法,又没说明得很清楚,看了几遍没看懂原理,只好自己动脑去想怎么实现O(N*V)算法。
若用F[i][j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值,并记m[i] = min(n[i], j / v[i])。放入背包的第i种物品的数目可以是:0、1、2……,可得:
F[i][j] = max { F[i - 1] [j – k * v[i] ] + k * w[i] } (0 <= k <= m[i]) ㈠
如何在O(1)时间内求出F[i][j]呢?
先看一个例子:取m[i] = 2, v[i] = v, w[i] = w, V > 9 * v,
并假设 f(j) = F[i - 1][j],观察公式右边要求最大值的几项:
j = 6*v: f(6*v)、f(5*v)+w、f(4*v)+2*w 这三个中的最大值
j = 5*v: f(5*v)、f(4*v)+w、f(3*v)+2*w 这三个中的最大值
j = 4*v: f(4*v)、f(3*v)+w、f(2*v)+2*w 这三个中的最大值
显然,公式㈠右边求最大值的几项随j值改变而改变,但如果将j = 6*v时,每项减去6*w,j=5*v时,每项减去5*w,j=4*v时,每项减去4*w,就得到:
j = 6*v: f(6*v)-6*w、f(5*v)-5*w、f(4*v)-4*w 这三个中的最大值
j = 5*v: f(5*v)-5*w、f(4*v)-4*w、f(3*v)-3*w 这三个中的最大值
j = 4*v: f(4*v)-4*w、f(3*v)-3*w、f(2*v)-2*w 这三个中的最大值
很明显,要求最大值的那些项,有很多重复。
根据这个思路,可以对原来的公式进行如下调整:
假设d = v[i],a = j / d,b = j % d,即 j = a * d + b,代入公式㈠,并用k替换a - k得:
F[i][j] = max { F[i - 1] [b + k * d] - k * w[i] } + a * w[i] (a – m[i] <= k <= a) ㈡
对F[i - 1][y] (y= b b+d b+2d b+3d b+4d b+5d b+6d … j)
F[i][j]就是求j的前面m[i] + 1个数对应的F[i - 1] [b + k * d] - k * w[i]的最大值,加上a * w[i],如果将F[i][j]前面所有的F[i - 1][b + k * d] – k * w放入到一个队列,那么,F[i][j]就是求这个队列最大长度为m[i] + 1时,队列中元素的最大值,加上a * w[i]。因而原问题可以转化为:O(1)时间内求一个队列的最大值。
该问题可以这样解决:
① 用另一个队列B记录指定队列的最大值(或者记录最大值的地址),并通过下面两个操作保证队列B的第一个元素(或其所指向的元素)一定是指定队列的当前最大值。
② 当指定队列有元素M进入时,删除队列B中的比M小的(或队列B中所指向的元素小等于M的)所有元素,并将元素M(或其地址)存入队列B。
③ 当指定队列有元素M离开时,队列B中的第一个元素若与M相等(或队列B第一个元素的地址与M相等),则队列B的第一个元素也离队。
经过上述处理,可以保证队列B中的第一个元素(或其指向的元素)一定是所指定队列所有元素的最大值。显然队列B的元素(或其所指向的元素)是单调递减的,这应该就是《背包九讲》中的提到的“单调队列”吧,初看的时候被这个概念弄得稀里糊涂,网上的资料提到“维护队列的最大值”,刚开始还以为是维护这个单调队列的最大值,对其采用的算法,越看越糊涂。其实,只要明白用一个“辅助队列”,求另一个队列的最值,那么具体的算法,和该“辅助队列”的性质(单调变化),都很容易推导出来。
在多重背包问题中,所有要进入队列的元素个数的上限值是已知的,可以直接用一个大数组模拟队列。
有N种物品和容量为V的背包,若第i种物品,容量为v[i],价值为w[i],共有n[i]件。怎样装才能使背包内的物品总价值最大?
网上关于“多重背包”的资料倒是不少,但是关于怎么实现O(N*V)算法的资料,真得好少呀,关于“单调队列”那部分算法,又没说明得很清楚,看了几遍没看懂原理,只好自己动脑去想怎么实现O(N*V)算法。
若用F[i][j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值,并记m[i] = min(n[i], j / v[i])。放入背包的第i种物品的数目可以是:0、1、2……,可得:
F[i][j] = max { F[i - 1] [j – k * v[i] ] + k * w[i] } (0 <= k <= m[i]) ㈠
如何在O(1)时间内求出F[i][j]呢?
先看一个例子:取m[i] = 2, v[i] = v, w[i] = w, V > 9 * v,
并假设 f(j) = F[i - 1][j],观察公式右边要求最大值的几项:
j = 6*v: f(6*v)、f(5*v)+w、f(4*v)+2*w 这三个中的最大值
j = 5*v: f(5*v)、f(4*v)+w、f(3*v)+2*w 这三个中的最大值
j = 4*v: f(4*v)、f(3*v)+w、f(2*v)+2*w 这三个中的最大值
显然,公式㈠右边求最大值的几项随j值改变而改变,但如果将j = 6*v时,每项减去6*w,j=5*v时,每项减去5*w,j=4*v时,每项减去4*w,就得到:
j = 6*v: f(6*v)-6*w、f(5*v)-5*w、f(4*v)-4*w 这三个中的最大值
j = 5*v: f(5*v)-5*w、f(4*v)-4*w、f(3*v)-3*w 这三个中的最大值
j = 4*v: f(4*v)-4*w、f(3*v)-3*w、f(2*v)-2*w 这三个中的最大值
很明显,要求最大值的那些项,有很多重复。
根据这个思路,可以对原来的公式进行如下调整:
假设d = v[i],a = j / d,b = j % d,即 j = a * d + b,代入公式㈠,并用k替换a - k得:
F[i][j] = max { F[i - 1] [b + k * d] - k * w[i] } + a * w[i] (a – m[i] <= k <= a) ㈡
对F[i - 1][y] (y= b b+d b+2d b+3d b+4d b+5d b+6d … j)
F[i][j]就是求j的前面m[i] + 1个数对应的F[i - 1] [b + k * d] - k * w[i]的最大值,加上a * w[i],如果将F[i][j]前面所有的F[i - 1][b + k * d] – k * w放入到一个队列,那么,F[i][j]就是求这个队列最大长度为m[i] + 1时,队列中元素的最大值,加上a * w[i]。因而原问题可以转化为:O(1)时间内求一个队列的最大值。
该问题可以这样解决:
① 用另一个队列B记录指定队列的最大值(或者记录最大值的地址),并通过下面两个操作保证队列B的第一个元素(或其所指向的元素)一定是指定队列的当前最大值。
② 当指定队列有元素M进入时,删除队列B中的比M小的(或队列B中所指向的元素小等于M的)所有元素,并将元素M(或其地址)存入队列B。
③ 当指定队列有元素M离开时,队列B中的第一个元素若与M相等(或队列B第一个元素的地址与M相等),则队列B的第一个元素也离队。
经过上述处理,可以保证队列B中的第一个元素(或其指向的元素)一定是所指定队列所有元素的最大值。显然队列B的元素(或其所指向的元素)是单调递减的,这应该就是《背包九讲》中的提到的“单调队列”吧,初看的时候被这个概念弄得稀里糊涂,网上的资料提到“维护队列的最大值”,刚开始还以为是维护这个单调队列的最大值,对其采用的算法,越看越糊涂。其实,只要明白用一个“辅助队列”,求另一个队列的最值,那么具体的算法,和该“辅助队列”的性质(单调变化),都很容易推导出来。
在多重背包问题中,所有要进入队列的元素个数的上限值是已知的,可以直接用一个大数组模拟队列。
0 0
- 多重背包O(N*V)算法详解(使用单调队列)(转)
- 多重背包O(N*V)算法详解(使用单调队列)
- 多重背包O(N*V)算法详解(使用单调队列)
- 多重背包O(N*V)算法详解(使用单调队列)
- 多重背包O(N*V)算法详解(使…
- 多重背包O(VN)算法——单调队列优化
- 多重背包问题 可行性问题O(V N) 算法
- Vijos P3677 多重背包(O(NC)) dp+单调队列
- 多重背包中多次背包 O(VN) 算法1 (单调队列优化) 带参考程序
- 多重背包中多次背包 O(VN) 算法1 (单调队列优化) 带参考程序
- HDU1059 单调队列优化 多重背包O(VN)
- HDU1171 单调队列优化多重背包O(VN)
- 单调队列多重背包时间复杂度O(vn)
- 多重背包(单调队列优化)
- poj 1742 多重背包(单调队列)
- 多重背包(单调队列优化)
- hdu1171 (单调队列优化多重背包)
- hdu 2191 多重背包基础题以及(单调队列O(vm))的用法
- 编程之美格格取数(为什么一直是WA,求测试)
- Hibernate 自动生成bo 映射是 default_schema 引发的问题
- 启动LFS,检测大多是FAIL,启动失败,电脑自动关机,需要重新编译LFS
- UNlit/Transparent 不发光透明shader
- 写COM组件用于ASP/PHP等动态网页
- 多重背包O(N*V)算法详解(使用单调队列)(转)
- linux内核分析--中断的分类
- (4)Struts2之Action
- C++ Primer笔记(五)语句
- 折半查找
- http://blog.csdn.net/duanyipeng/article/details/7024897 Cursor的moveToFirst和moveToNext
- 4.0上全屏显示
- hibernate之上的schema属性
- Java:String和Date、Timestamp之间的转换