算法导论 第四部分——基本数据结构——第15章:动态规划:背包问题
0-1背包问题描述
有一个窃贼在偷窃一家商店时发现有n件物品,第i件物品价值为vi元,重量为wi,假设vi和wi都为整数。他希望带走的东西越值钱越好,但他的背包中之多只能装下W磅的东西,W为一整数。他应该带走哪几样东西?
0-1背包问题中:每件物品或被带走,或被留下,(需要做出0-1选择)。小偷不能只带走某个物品的一部分或带走两次以上同一个物品。
比较好的介绍博客:
http://www.importnew.com/13072.html http://blog.csdn.net/wangyuquanliuli/article/details/46628357 http://www.cnblogs.com/fly1988happy/archive/2011/12/13/2285377.html0-1背包问题解决方法
0-1背包问题是个典型举办子结构的问题,但是只能采用动态规划来解决,而不能采用贪心算法。因为在0-1背包问题中,在选择是否要把一个物品加到背包中,必须把该物品加进去的子问题的解与
不取该物品的子问题的解进行比较。这种方式形成的问题导致了许多重叠子问题,满足动态规划的特征。动态规划解决0-1背包问题步骤如下:
0-1背包问题子结构:选择一个给定物品i,则需要比较选择i的形成的子问题的最优解与不选择i的子问题的最优解。分成两个子问题,进行选择比较,选择最优的。
0-1背包问题递归过程:设有n个物品,背包的重量为w,C[i][w]为最优解。即:
实现代码如下: 空间复杂度还可以简化为 v+1 而不是原来的(n+1)*(v+1) 。因为每次计算其实所需要的数据都是上一组数组,所以不需要记住前面的很多组数。
#include <iostream> #include <vector> using namespace std; const int MIN=0x80000000; const int N=3; //物品数量 const int V=5; //背包容量 int f[N+1][V+1]; int Package(int *W,int *C,int N,int V); void main(int argc,char *argv[]) { int W[4]={0,7,5,8}; //物品权重 int C[4]={0,2,3,4}; //物品大小 int result=Package(W,C,N,V); if(result>0) { cout<<endl; cout<<"the opt value:"<<result<<endl; int i=N,j=V; while(i) { if(f[i][j]==(f[i-1][j-C[i]]+W[i])) { cout<<i<<":"<<"w="<<W[i]<<",c="<<C[i]<<endl; j-=C[i]; } i--; } } else cout<<"can not find the opt value"<<endl; return; } int Package(int *W,int *C,int N,int V) { int i,j; memset(f,0,sizeof(f)); //初始化为0 for(i=0;i<=N;i++) for(j=1;j<=V;j++) //此步骤是解决是否恰好满足背包容量, f[i][j]=MIN; //若“恰好”满足背包容量,即正好装满背包,则加上此步骤,若不需要“恰好”,则初始化为0 for(i=1;i<=N;i++) for(j=C[i];j<=V;j++) { f[i][j]=(f[i-1][j]>f[i-1][j-C[i]]+W[i])?f[i-1][j]:(f[i-1][j-C[i]]+W[i]); cout<<"f["<<i<<"]["<<j<<"]="<<f[i][j]<<endl; } return f[N][V]; }
梦想不是浮躁,而是沉淀和积累