原题
http://acm.hdu.edu.cn/showproblem.php?pid=2602
题目大意
题目大概是讲有一个背包(给容量),然后又一排骨头,骨头有体积和价值,你要用这个背包装这些骨头,使骨头的价值之和最大化,并输出该值.
题目分析
标准的01背包模板.这里讲一下01背包的更新过程,首先设一个dp数组(一维),dp[i]表示用i格容量最多能装多少价值的东西,数组初始化为-1(dp[0]=0).要更新这个dp数组,先用一个外循环来遍历每个物品,然后内循环从背包容量大小开始往前更新,(这里w[i]使每个物品的体积,v[i]使每个物品的价值,j是内循环变量)也就是if(dp[j-w[i]]更新过,这里是dp[j-w[i]]!=-1) dp[j]=max(dp[j],dp[j-w[i]]+v[i])(注意一下i-w[i]不要越界),这里从后往前更新的原因是这样子能保证每个物品只装一次,这也是和完全背包的区别,想一下如果从前往后更新的话,这里假设i=1,w[1]=1,v[1]=1,外循环扫第一遍时即i=1,如果从后往前更新,则有if(dp[j]!=-1) dp[j+w[i]]=max(dp[j+w[i]],dp[j]+v[i])(同样注意i+w[i]不要越界),当内循环扫到0时,更新dp[1]=1,然后内循环到2,更新dp[2]=1,这里就开始错了,因为这时候dp[2]已经装了两个第1个物品了.
代码
1 #include <cstdio> 2 #include <cmath> 3 #include <iostream> 4 #include <cstring> 5 #include <algorithm> 6 #include <vector> 7 #include <string> 8 #include <utility> 9 #include <queue> 10 #include <stack> 11 const int INF=0x3f3f3f3f; 12 using namespace std; 13 14 const int Max=1000; 15 int dp[Max+1]; 16 int w[Max+1],v[Max+1]; 17 18 int main() 19 { 20 int t; 21 cin>>t; 22 while(t--) 23 { 24 int n,k; 25 memset(w,0,sizeof(w)); 26 memset(v,0,sizeof(v)); 27 cin>>n>>k; 28 for(int i=1;i<=n;i++) 29 cin>>v[i]; 30 for(int i=1;i<=n;i++) 31 cin>>w[i]; 32 memset(dp,-1,sizeof(dp)); 33 dp[0]=0; 34 for(int i=1;i<=n;i++) 35 for(int j=k;j>=w[i];j--) //j>=w[i]保证不越界 36 if(dp[j-w[i]]!=-1) dp[j]=max(dp[j],dp[j-w[i]]+v[i]); 37 int ans=0; 38 for(int i=1;i<=k;i++) //扫一遍dp数组里的最大值 39 if(ans<dp[i]) ans=dp[i]; 40 cout<<ans<<endl; 41 } 42 return 0; 43 }