0-1背包使用一维数组
2014-02-19 10:58
239 查看
使用滚动数组将空间优化到了2*V,在背包九讲中提到了使用一维数组也可以达到同样的效果,个人认为这也是滚动思想的一种,由于使用一维数组解01背包会被多次用到,完全背包的一种优化实现方式也是使用一维数组,所以我们有必要理解这种方法。
如果只使用一维数组f[0…v],我们要达到的效果是:第i次循环结束后f[v]中所表示的就是使用二维数组时的f[i][v],即前i个物体面对容量v时的最大价值。我们知道f[v]是由两个状态得来的,f[i-1][v]和f[i-1][v-c[i]],使用一维数组时,当第i次循环之前时,f[v]实际上就是f[i-1][v],那么怎么得到第二个子问题的值呢?事实上,如果在每次循环中我们以v=v…0的顺序推f[v]时,就能保证f[v-c[i]]存储的是f[i-1][v-c[i]]的状态。状态转移方程为:
1
v = V...0; f(v) = max{ f(v), f(v-c[i])+w[i] }
我们可以与二维数组的状态转移方程对比一下
1
f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }
正如我们上面所说,f[v-c[i]]就相当于原来f[i-1][v-c[i]]的状态。如果将v的循环顺序由逆序改为顺序的话,就不是01背包了,就变成完全背包了,这个后面说。这里举一个例子理解为何顺序就不是01背包了
假设有物体z容量2,价值vz很大,背包容量为5,如果v的循环顺序不是逆序,那么外层循环跑到物体z时,内循环在v=2时,物体z被放入背包,当v=4时,寻求最大价值,物体z放入背包,f[4]=max{f[4],f[2]+vz},这里毫无疑问后者最大,那么此时f[2]+vz中的f[2]已经装入了一次物体z,这样一来该物体被装入背包两次了就,不符合要求,如果逆序循环v,这一问题便解决了。
代码如下,为了加深理解,可以在内循环结束输出每一个状态的情况到文本中,会发现与使用二维数组时的状态转移矩阵都是一样一样的。
可以看出,使用一维数组,代码非常简练。
========================================
如果只使用一维数组f[0…v],我们要达到的效果是:第i次循环结束后f[v]中所表示的就是使用二维数组时的f[i][v],即前i个物体面对容量v时的最大价值。我们知道f[v]是由两个状态得来的,f[i-1][v]和f[i-1][v-c[i]],使用一维数组时,当第i次循环之前时,f[v]实际上就是f[i-1][v],那么怎么得到第二个子问题的值呢?事实上,如果在每次循环中我们以v=v…0的顺序推f[v]时,就能保证f[v-c[i]]存储的是f[i-1][v-c[i]]的状态。状态转移方程为:
1
v = V...0; f(v) = max{ f(v), f(v-c[i])+w[i] }
我们可以与二维数组的状态转移方程对比一下
1
f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }
正如我们上面所说,f[v-c[i]]就相当于原来f[i-1][v-c[i]]的状态。如果将v的循环顺序由逆序改为顺序的话,就不是01背包了,就变成完全背包了,这个后面说。这里举一个例子理解为何顺序就不是01背包了
假设有物体z容量2,价值vz很大,背包容量为5,如果v的循环顺序不是逆序,那么外层循环跑到物体z时,内循环在v=2时,物体z被放入背包,当v=4时,寻求最大价值,物体z放入背包,f[4]=max{f[4],f[2]+vz},这里毫无疑问后者最大,那么此时f[2]+vz中的f[2]已经装入了一次物体z,这样一来该物体被装入背包两次了就,不符合要求,如果逆序循环v,这一问题便解决了。
代码如下,为了加深理解,可以在内循环结束输出每一个状态的情况到文本中,会发现与使用二维数组时的状态转移矩阵都是一样一样的。
#include using namespace std; int maxV[201]; int weight[11]; int value[11]; int V, N; void main() { int i, j; scanf("%d %d",&V,&N); for(i = 0; i < N;++i) { scanf("%d%d",&weight[i],&value[i]); } for(i = 0; i < N;++i) { for(j = V; j >= weight[i]; --j) { int tmp =maxV[j-weight[i]]+value[i]; maxV[j] =(maxV[j] > tmp) ? maxV[j] : tmp; } } printf("%d",maxV[V]); }
可以看出,使用一维数组,代码非常简练。
========================================
相关文章推荐
- 0-1背包使用滚动数组压缩空间
- 01背包问题-基本实现
- 完全背包使用一维数组
- 完全背包中的逆向思维
- 完全背包基本实现
- 最长递增子序列(LIS)
- C++中cin、cin.get()、cin.getline…
- scanf()与gets()的冲突
- 最长公共子序列(LCS)
- 01背包问题
- 新的开始
- with check option
- U盘安装CentOS+Windows 7双系统
- 小析MBR、boot、GRUB的关系
- android多点触控统一的原理(使用event.getAction()&MotionEvent.ACTION_MASK的原因)
- C语言的那些秘密之---函数返回局部…
- 获取存储过程返回值
- C++中的四舍五入方法
- 存储过程与函数的区别
- 打不开RSA密钥容器