0-1背包和完全背包
来源:互联网 发布:linux oracle lsnrctl 编辑:程序博客网 时间:2024/06/05 09:39
一.0-1背包
1.0-1背包指的是每件物品要么取一次,要么不取,目的是找到装到背包里最大价值。c[N]代表物体重量,w[N]代表物体价值,V代表背包容量。
2.时间复杂度:O(N*V) N指的是物品个数,V指的是背包的容量,这是最优情况,无法再优。
3.空间复杂度:原始:f[N+1][V+1]———>改进:f[V+1];
(1)如果没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为 0。
(2)如果要求恰好装满背包,那么在初始化时除了f[0]为 0,其它f[1..V]均设为-∞,这样就可以保证最终得到的 f[N]是一种恰好装满背包的最优解。
5.0-1背包改进算法第二重循环为何逆序的分析
for(i=0;i<N;i++)
for(v=V;v>=c[i];v--) //这里为何要逆序?
f[v]=max(f[v],f[v-c[i]]+w[i]); 【1】
分析:由原始的状态转移方程可知当v>=c[i]时,f[i][v]=max{f[i-1][v-c[i]]+w[i],f[i-1][v]}。 【2】 ‚
要保证第i次循环中的状态 f[i][v]是由状态f[i-1][v-c[i]]递推而来,即如何保证【1】中f[v-c[i]]是【2】中的f[i-1][v-c[i]]。
为直观看出画图如下:
从图中可以看出,当第二重循环正序时,当扫到点3的时候,f[v-c[i]]的值并不是f[i-1][v-c[i]],
而是f[i][v-c[i]]。只有逆序的时候才可以做到要求的那样。
二.完全背包(只给出一种O(N*V)算法)
1.完全背包:各物品可以无限取。
2.时间复杂度:O(N*V)
3.空间复杂度:f[V+1];
三.0-1背包和完全背包的对比情况:
因为0-1背包每件物品只能取一次,而完全背包不限取的次数。
0-1背包: f[i][v]=max{f[i-1][v-c[i]]+w[i] ,f[i-1][v]}
要么取第i种物品,问题转化为前i-1种物品放入剩下的容量为v-c[i]的背包中。
要么不取第i种物品,问题转化为前i-1种物品放入容量为v的背包中。
完全背包: f[i][v]=max{f[i][v-c[i]]+w[i],f[i-1][v]}
要么取第i种物品,问题转化为前i种物品放入剩余的容量为v-c[i]的背包中。
要么不取第i种物品,问题转化为前i-1种物品放入容量为v的背包中。
对于完全背包用一维数组:
for(i=0;i<N;i++)
for(v=c[i];v<=V;v++)
f[v]=max(f[v],f[v-c[i]]+w[i]);
这里的第二重循环必须得正序,因为只有正序才能保证max里面的f[v-c[i]]是f[i][v-c[i]]。
四.示例w[4]={30,14,16,20}//各物品价值
c[4]={6,3,4,2}//各物品重量
设背包容量为V
五.代码清单
#include <stdio.h>#include <stdlib.h>#define MIN -32768int max(int a,int b){ return a>b?a:b;}//0-1背包int knapSack_01_Bas(int w[],int c[],int N,int V){ int f[N+1][V+1]; int i=0; int v=0; for(i=0;i<=N;i++) { for(v=0;v<=V;v++) { if(i==0||v==0) f[i][v]=0; else if(c[i-1]>v) f[i][v]=f[i-1][v]; else f[i][v]=max(f[i-1][v],f[i-1][v-c[i-1]]+w[i-1]); } } if(f[N][V]<0) f[N][V]=0; return f[N][V];}int knapSack_01_Bas_fill(int w[],int c[],int N,int V){ int f[N+1][V+1]; int i=0; int v=0; for(i=0;i<=N;i++) { for(v=0;v<=V;v++) { if(i==0&&v!=0) f[0][v]=MIN; else if(v==0) f[i][0]=0; else if(c[i-1]>v) f[i][v]=f[i-1][v]; else f[i][v]=max(f[i-1][v],f[i-1][v-c[i-1]]+w[i-1]); } } if(f[N][V]<0) f[N][V]=0; return f[N][V];}int knapSack_01_Pro(int w[],int c[],int N,int V){ int f[V+1]; int i=0; int v=0; /* f[0]=0; for(i=1;i<=V;i++) { f[i]=MIN; } */ for(i=0;i<=V;i++){ f[i]=0; } for(i=0;i<N;i++) for(v=V;v>=c[i];v--) f[v]=max(f[v],f[v-c[i]]+w[i]); if(f[V]<0) f[V]=0; return f[V];}int knapSack_01_Pro_fill(int w[],int c[],int N,int V){ int f[V+1]; int i=0; int v=0; f[0]=0; for(i=1;i<=V;i++) { f[i]=MIN; } /* for(i=0;i<=V;i++){ f[i]=0; } */ for(i=0;i<N;i++) for(v=V;v>=c[i];v--) f[v]=max(f[v],f[v-c[i]]+w[i]); if(f[V]<0) f[V]=0; return f[V];}//完全背包int knapSack_complete(int w[],int c[],int N,int V){ int f[V+1]; int i=0; int v=0; for(i=0;i<=V;i++){ f[i]=0; } for(i=0;i<N;i++) for(v=c[i];v<=V;v++) f[v]=max(f[v],f[v-c[i]]+w[i]); if(f[V]<0) f[V]=0; return f[V];}int main(){ int w[4]={30,14,16,20};//价值 int c[4]={6,3,4,2};//重量 int V=15;//背包容量 int i=0; for(i=0;i<=V;i++) printf("Basic--V=%d,max value:%d\n",i,knapSack_01_Bas(w,c,4,i)); for(i=0;i<=V;i++) printf("Basic fill knapSack--V=%d,max value:%d\n",i,knapSack_01_Bas_fill(w,c,4,i)); for(i=0;i<=V;i++) printf("Pro--V=%d,max value:%d\n",i,knapSack_01_Pro(w,c,4,i)); for(i=0;i<=V;i++) printf("Pro fill knapSack--V=%d,max value:%d\n",i,knapSack_01_Pro_fill(w,c,4,i)); for(i=0;i<=V;i++) printf("Complete knapSack--V=%d,max value:%d\n",i,knapSack_complete(w,c,4,i)); return 0;}
- 0-1背包和完全背包
- 0-1背包和完全背包问题
- 0-1背包、部分背包和完全背包模板
- 0-1背包----完全背包
- 背包问题(0-1背包、完全背包、多重背包)详解
- 0-1背包问题和完全背包问题
- 动态规划学习之0-1背包和完全背包
- 0/1背包问题和完全背包问题
- 0-1背包和完全背包问题辨析
- 0-1背包和完全背包问题应用
- 0/1背包与完全背包
- HDU 5410 (0 1背包+ 完全背包)
- 01背包和完全背包
- 01背包和完全背包
- 01背包和完全背包
- 01背包和完全背包
- 01背包和完全背包
- 0/1背包,完全背包,多重背包方程
- Android ListView圆角实现
- 其中的一个作业
- 【备注】【C15】《21天学通Java(第6版)》 .(美)Rogers.Cadenhead著 PDF下载
- 【Java】java中的set()和get()方法理解和使用
- 我拿到需求该怎么开始写Android项目
- 0-1背包和完全背包
- SQLite 事务
- t检验
- 变量和作用域
- common-pool2对象池的详解与使用
- 在网页上生成由字母和数字组成验证码的简单实现
- mac 安装tesseract-ocr
- Ubuntu安装Code::Blcoks16.01
- 《肖申克的救赎》