0-1背包
2015-11-12 21:41
162 查看
有n种物品,第i种物品的体积为V[i],重量为W[i],选一些物品放到容量为c的背包里,使得背包内的物品在总体积不超过C的前提下重量尽量大。
用d(i,j)表示当前处于第i层,背包的剩余重量为j,通俗点说就是把 i i+1 i+2 .....n 个物品装到容量为j的背包中的最大总重量。
所以我们得到的状态转移方程为:
d(i+1,j) ( 0=<j<v[i])
d(i,j)= max( d(i+1,j) , d(i+1,j-v[i])+w[i] ) (j>v[i])
最终的答案为 d(1,c)
聪明的读者也许看出来了,还有另外一种对称的状态的定义:
用f(i,j) 表示把前i个物品装到容量为j的背包中的最大重量,其转移方程也不难得出
f(i,j)=max(f(i-1,j),f(i-1,j-v[i])+w[i])
最终的答案为 f(n,c);
于是上面的代码就可以改写为
看上去两种方式是完全对称的,但是还是有细微差别的,新的允许边读边写,而不必把w,v保存下来。
更为奇妙的是还可以把数组f变成一维:
值得注意的是j一定要逆序。
如果是顺序的话,在一次i的循环中就会利用前面的结果,从而导致不是在这一次中放一个物品,而是多个的假象,读者可以自行试试。
在递推法中,如果计算顺序很特殊,而且计算新状态所用到的原状态不多的话,可以尝试用滚动数组来减少内存开销。
用d(i,j)表示当前处于第i层,背包的剩余重量为j,通俗点说就是把 i i+1 i+2 .....n 个物品装到容量为j的背包中的最大总重量。
所以我们得到的状态转移方程为:
d(i+1,j) ( 0=<j<v[i])
d(i,j)= max( d(i+1,j) , d(i+1,j-v[i])+w[i] ) (j>v[i])
最终的答案为 d(1,c)
#include<iostream> #define MAX 100 using namespace std; int main(){ int n,c; int d[MAX][MAX]; int v[MAX],w[MAX]; while(cin>>n>>c){ memset(d,0,sizeof(d)); for(int i=1;i<=n;i++) cin>>v[i]>>w[i]; for(int i=n;i>=1;i--){ for(int j=0;j<=c;j++){ d[i][j]=(i==n ? 0: d[i+1][j]) ; if(j>=v[i]) d[i][j]=max(d[i][j],d[i+1][j-v[i]]+w[i]); } } cout<<d[1][c]<<endl; } return 0; }
聪明的读者也许看出来了,还有另外一种对称的状态的定义:
用f(i,j) 表示把前i个物品装到容量为j的背包中的最大重量,其转移方程也不难得出
f(i,j)=max(f(i-1,j),f(i-1,j-v[i])+w[i])
最终的答案为 f(n,c);
于是上面的代码就可以改写为
for(int i=1;i<=n;i++){ for(int j=0;j<=c;j++){ f[i][j]=(i==1?0:f[i-1][j]); (if j>=v[i] )f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]); } }
看上去两种方式是完全对称的,但是还是有细微差别的,新的允许边读边写,而不必把w,v保存下来。
for(int i=1;i<=n;i++){ for(int j=0;j<=c;j++){ cin>>v>>w; f[i][j]=(i==1?0:f[i-1][j]); f[i][j]=max(f[i][j],f[i-1][j-v]+w); } }
更为奇妙的是还可以把数组f变成一维:
for(int i=1;i<=n;i++){ cin>>v>>w; for(int j=c;j<=0;j--){ if(j>=v){ f[j]=max(f[j],f[j-v]+w); } } }
值得注意的是j一定要逆序。
如果是顺序的话,在一次i的循环中就会利用前面的结果,从而导致不是在这一次中放一个物品,而是多个的假象,读者可以自行试试。
在递推法中,如果计算顺序很特殊,而且计算新状态所用到的原状态不多的话,可以尝试用滚动数组来减少内存开销。
相关文章推荐
- 测试文档
- Spark1.5.0 + Hadoop2.7.1整合
- 为Sublime Text安装smali代码语法高亮插件
- newmat乔里斯基分解
- UML图中类之间的关系:依赖,泛化,关联,聚合,组合,实现
- 35.Android .gitignore 模板
- 获取文字宽度
- swift UIView实现可视化自定义组件
- swift UIView实现可视化自定义组件
- U盘批处理复制所有文件
- H5
- Codeforces 513B2 Permutations
- ubuntu 编译openpts
- 统计给定的n个数中,负数、零和正数的个数。输入数据有多组,每组占一行,每行的第一个数是整数n(n<100),表示需要统计的数值的个数,然后是n个实数;如果n=0,则表示输入结束,该行不做处理。
- MapReduce编程实战(二)——20151112
- 初步学习的一些感悟
- JAVA经典及细节总结
- C#WebBrowser控件使用教程与技巧收集
- ***iOS学习之Table View的简单使用和DEMO示例(共Plain普通+Grouped分组两种)
- listView 解决焦点冲突问题 item项和子控件之间的冲突