0-1背包
来源:互联网 发布:2016淘宝客微信教程 编辑:程序博客网 时间:2024/05/21 20:13
背包是一类典型的动归问题,有大神总结出来的背包九讲,0-1背包是其中的一种,也是最基本的一种。
之所以叫做 0-1背包是因为,这类问题中的每一件物体只有一件,放入背包与不放就构成了它的两种状态,0 代表不放,1 代表放入。
将这类问题总结一下就是:
解这道题的中点就在于,对于上面这个状态转移方程的理解。也就是把i个物品放入重量限制为W背包的中所取得的最大价值,取决于第i个物品的两种状态,即放与不放。
放,由于它会占有一定的重量,所以能取得的价值为v[i](它本身的价值)+Value(i-1, w-w[i])(前i-1件物品放入重量限制为w-w[i]的背包能取得的最大价值);
不放(放不下也属于),所能取得的价值就是Value(i-1, w)(即前i-1件物品放入重量限制为w的背包中)。
Value(i, w)即i件物品放入重量限制为w的背包中的最大价值就等于上面两种情况中的最大值。
这是一个动归理解的思想,我们在将它自底向上倒回去实现。
例如, 存在一个背包重量限制为10, 有5个物品重量价值分别为(5, 1)(2, 4)(3, 3)(4, 2)(5, 1),求最大价值。
此时我们用一个二位数组来记录对应的每一个value(i,w),从第一个物品开始放起,算出每一种情况下的最大价值,并逐步退出最终的解,即在重量限制10下,所能获得的最大价值。
类似于数字塔一样,我们可以从第一个物品开始装,并计算出各个情况下最大的价值,这样就可以依次计算二维数组中每一层的结果,最后输出[5,10]即在重量限制为10时放入第5个物品的最大价值。以这一题为例,结果就是v[5, 10] = 14。
例如:poj 3624 Charm Bracelet
Problem Description
Bessie has gone to the mall’s jewelry store and spies a charm bracelet. Of course, she’d like to fill it with the best charms possible from the N (1 ≤ N ≤ 3,402) available charms. Each charm i in the supplied list has a weight Wi (1 ≤ Wi ≤ 400), a ‘desirability’ factor Di (1 ≤ Di ≤ 100), and can be used at most once. Bessie can only support a charm bracelet whose weight is no more than M (1 ≤ M ≤ 12,880).Given that weight limit as a constraint and a list of the charms with their weights and desirability rating, deduce the maximum possible sum of ratings.
Input
- Line 1: Two space-separated integers: N and M
- Lines 2..N+1: Line i+1 describes charm i with two space-separated integers: Wi and Di
Output
- Line 1: A single integer that is the greatest sum of charm desirabilities that can be achieved given the weight constraints
Sample Input
4 6
1 4
2 6
3 12
2 7
Sample Output
23
按照我们上面的思路我们就可以写出这样的代码
#include <iostream>#include <algorithm>using namespace std;int w[3500], d[3500];int f[13000][13000];int main(){ int n, wl; cin>>n>>wl; for(int i=1; i<=n; i++) cin>>w[i]>>d[i]; for(int i=1; i<=n; i++) { for(int j=1; j<=wl; j++) { if(j>=w[i]) f[i][j] = max(f[i-1][j], f[i-1][j-w[i]]+d[i]); else f[i][j] = f[i-1][j]; } } cout<<f[n][wl]<<"\n";}
但事实上我们这样是过不了的,在其他oj上面可能有数据量比较小的题可以过,但是对于这道题来说,是会这样的Memory Limit Exceeded
。
其实也很好解决,因为我们仔细观察就可以发现,我们从底层往上推的时候,实际上只用到了当前的和上一列,此时我们就可以让数组变成这样 f[2][13000]。
for(int i=1; i<=n; i++) { for(int j=1; j<=wl; j++) { if(j-w[i]>=0) f[1][j] = max(f[0][j], f[0][j-w[i]]+d[i]); else f[1][j] = f[0][j]; } for(int j=0; j<=wl; j++) f[0][j] = f[1][j]; }
相当于滚动着去利用这个数组,这样做后,我们会发现,两列其实也是没必要的,可以利用一个一维数组,因为要用到前面的值,所以我们每一行的推导,变成从后往前,就不会影响到值的变化了。
#include <iostream>#include <algorithm>using namespace std;int w[3500], d[3500];int f[13000];int main(){ int n, wl; cin>>n>>wl; for(int i=1; i<=n; i++) cin>>w[i]>>d[i]; for(int i=1; i<=n; i++) { for(int j=wl; j>=1; j--) { if(j-w[i]>=0) f[j] = max(f[j], f[j-w[i]]+d[i]); else f[j] = f[j]; } } cout<<f[wl]<<"\n";}
- 背包问题(0-1背包、完全背包、多重背包)详解
- 0-1背包----完全背包
- 0-1背包+分数背包
- 背包问题之0/1背包,完全背包,多重背包,混合背包
- 【背包问题】背包问题之0-1背包、完全背包、多重背包
- 0/1背包,完全背包,多重背包方程
- 0-1背包、部分背包和完全背包模板
- 背包问题(0/1背包,完全背包)
- 背包笔记-含0/1背包问题、完全背包问题、多重背包问题、二维背包问题、分组背包问题
- 0/1背包与完全背包
- 背包问题之0-1背包(一)
- 背包问题之0-1背包(二)
- 背包问题之0-1背包(三)
- 背包问题和0-1背包问题
- 背包问题start...:0-1背包
- 多重背包转换成0-1背包
- 贪心背包和0-1背包问题
- 0-1背包和部分背包问题
- Amazon EC2 Container Service笔记
- MySQL性能优化
- 函数参数异同(值传递、指针传递、引用传递)
- windows环境配置groovy
- 简单理解ThreadLocal
- 0-1背包
- 负数在计算机中的表示
- 【暑假测试3】C HDU 5327 Olympiad
- UI 03 关于UITextField键盘遮挡问题
- 字典序排列的算法
- 学习C++11之引用
- HTTP中POST与GET 区别介绍
- Android基础之Activity四种启动模式
- Contiki例(三)使用etimer定时器激活被阻塞的任务