0-1背包的二维实现及一维实现
2015-01-26 15:08
281 查看
一、二维实现
参考资料:《算法设计与分析基础》P228-P230
http://blog.csdn.net/tjyyyangyi/article/details/7929665 http://www.cnblogs.com/SDJL/archive/2008/08/22/1274312.html
二、空间压缩(一维实现)
如果只用一个数组f[0..v],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?
由二维递推公式:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]},可知 i 行的状态是由i-1行的两个状态递推得到。若采用一维数组必然存在覆盖现象,又f[i-1][v-c[i]]一定是在f[i-1][v]的前面,所以如果是
for v=0..V 顺序的话,首先被覆盖(在第i行,求f [i] [ v - c[i] ](这里仅仅把 v
- c[i] 视为一个下标v),求得的值就放在了这个原来f[i-1][v-c[i]]所在的位置)的是f[v-c[i]](相当于二维数组的 f[i-1][v-c[i]]),代之以二位数组的f[i][v-c[i]],
那么到后面求 f[i][v]时,就变成了由f[i][v-c[i]]推知 f[i][v],这显然不对,为避免这一情况的发生,可以逆序覆盖,即
for i=1..N
for v=V..1 //对的,V是目标承重(最大承重);对于每一行(i),v都要取遍1到V所有的值(v=0在初始化时设置过了)
f[v]=max{f[v],f[v-c[i]]+w[i]};
使用的特性就是求后面的值只会用到前面的值(实质是上一轮保留(求得)的值—f[v-c[i]](实质是 f[i-1][v-c[i]]))和它本身的值(实质也是上一轮保留(求得)的值—f[v](实质是 f[i-1][
v ]))来递推,而前面的值却不会用到后面的值来递推。因此后面的值先被覆盖是没有关系的(反正又不用)
![](http://img.blog.csdn.net/20150129210707066?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTEFOR1FJTkcxMjM0NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
参考文章:http://blog.csdn.net/hackbuteer1/article/details/7178358
参考资料:《算法设计与分析基础》P228-P230
http://blog.csdn.net/tjyyyangyi/article/details/7929665 http://www.cnblogs.com/SDJL/archive/2008/08/22/1274312.html
#include<stdio.h> int f[10][100]; //构造最优矩阵 void package0_1(int *w,int *v,int n,int c) { int i,j; //初始化矩阵 for(i=1;i<=n;i++) f[i][0] = 0; for(j=1;j<=c;j++) f[0][j] = 0; for(i=1;i<=n;i++) { for(j=1;j<=c;j++) { //当容量够放入第i个物品,并且放入之后的价值要比不放大 if(w[i] <= j && f[i-1][j-w[i]] + v[i] > f[i-1][j]) { f[i][j] = f[i-1][j-w[i]] + v[i]; }else f[i][j] = f[i-1][j]; } } printf("最大价值: %d \n",f [c]); } //构造最优解(回溯) void getResult(int n,int c,int *res,int *v,int *w) { int i,j; j = c; for(i=n;i>=1;i--) { if(f[i][j] != f[i-1][j]) { res[i] = 1; j = j - w[i]; } } } void main() { int w[6] = {0,2,2,6,5,4};//每个物品的重量 int v[6] = {0,6,3,5,4,6};//每个物品的价值 int res[5] = {0,0,0,0,0}; int n = 5; //物品的个数 int c = 10; //背包能容的重量 int i,j; package0_1(w,v,n,c); for(i=0;i<=n;i++) { for(j=0;j<=c;j++) printf("%2d ",f[i][j]); printf("\n"); } getResult(n,c,res,v,w); printf("放入背包的物品为: \n"); for(i=1;i<=n;i++) if(res[i] == 1) printf("%d ",i); }
二、空间压缩(一维实现)
如果只用一个数组f[0..v],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?
由二维递推公式:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]},可知 i 行的状态是由i-1行的两个状态递推得到。若采用一维数组必然存在覆盖现象,又f[i-1][v-c[i]]一定是在f[i-1][v]的前面,所以如果是
for v=0..V 顺序的话,首先被覆盖(在第i行,求f [i] [ v - c[i] ](这里仅仅把 v
- c[i] 视为一个下标v),求得的值就放在了这个原来f[i-1][v-c[i]]所在的位置)的是f[v-c[i]](相当于二维数组的 f[i-1][v-c[i]]),代之以二位数组的f[i][v-c[i]],
那么到后面求 f[i][v]时,就变成了由f[i][v-c[i]]推知 f[i][v],这显然不对,为避免这一情况的发生,可以逆序覆盖,即
for i=1..N
for v=V..1 //对的,V是目标承重(最大承重);对于每一行(i),v都要取遍1到V所有的值(v=0在初始化时设置过了)
f[v]=max{f[v],f[v-c[i]]+w[i]};
使用的特性就是求后面的值只会用到前面的值(实质是上一轮保留(求得)的值—f[v-c[i]](实质是 f[i-1][v-c[i]]))和它本身的值(实质也是上一轮保留(求得)的值—f[v](实质是 f[i-1][
v ]))来递推,而前面的值却不会用到后面的值来递推。因此后面的值先被覆盖是没有关系的(反正又不用)
参考文章:http://blog.csdn.net/hackbuteer1/article/details/7178358
相关文章推荐
- 知识点:01背包(多种姿势:二维实现+一维实现+滚动数组实现+背包装满+输出最优方案)
- HDU 2602 Bone Collector(01二维背包&一维背包&滚动数组优化二维背包的原理 )
- DP背包问题小结(01背包,完全背包,需恰好装满或不需,一维DP、二维DP)
- nyoj 289 苹果(01背包一维和二维实现)
- HDU 3008 dp打怪血量 三重循环调二维背包或一维
- HDU - 2159 - FATE 【二维完全背包,和一维差不多呀】
- python用quad、dblquad实现一维二维积分范例
- >+ ASP模板类[实现一维循环和二维循环,可以从文件、数据库、变量取摸板]
- dp之01背包(从二维到一维)+完全背包
- [LeetCode] 二维背包问题 Ones and zeros 另含两种一维背包问题
- PHP实现判断数组是一维、二维或几维的方法
- 实现动态分配一维,二维,三维数组
- hdu--2159--二维费用背包<一维错误解法>
- 简单的01背包 HDU - 2602 1864 二维、一维数组
- 背包问题非递归实现
- Datagridview 实现二维表头
- VS.NET打印思想与2003/5DataGrid、DataGridView及二维数据如ListView等终极打印实现(全部源码)
- 背包问题算法的JAVA实现
- 完全背包问题(Java实现)
- Datagridview 实现二维表头