0-1背包问题
输入数据
T表示有T组数据
然后分别输入T组
第一行为物品个数N,背包容量V
第二行为物品价值
第三行为物品占用体积
输出最大价值量
Input
1
5 10
1 2 3 4 5
5 4 3 2 1
Output
14
首先考虑动态规划
将物品个数和背包容量想象为二维数组,行用i表示面临的第i个物品的选择,列用j表示背包容量为j的情况下最优的装载价值。
然后我们开始模拟从第一个物品开始挑选的过程,用两个for循环来模拟这个过程:
for(int i=1;i<=N;i++)
{
for(int j=0;j<=V;j++)//注意j从0开始
{
if(j>=w[i])
s[i][j]=max(s[i-1][j],s[i-1][j-w[i]]+v[i]);
else
s[i][j]=s[i-1][j];
}
}
模拟一下过程哈
首先挑选第一个物品,价值1,体积5,在第一个for循环中进行第二个对背包的体积进行的for循环,体积小于5之前的价值s[i][j]肯定都是0不用多讲,从体积大于等于5开始,背包能装入的价值量为1了,第1行后面都一样,接着我们来看第2行。
第二行是第一个for循环循环到i=2的情况,开始挑选第二个物品,还是从体积为1开始循环,直到体积为4可以装第二个物品了,所以s[2][4]=2了,然后关键的地方来了,到体积为5的时候,5>4,所以s[2][5]=s[2-1][5]或者s[2-1][5-物品2的体积]+物品2的价值(也就是s[i-1][j-w[i]]+v[i]),在这里当背包容量大于等于这个挑选的物品时,可以分为两种情况:①不选就等于s[i-1][j]②选则等于s[i-1][j-w[i]]+v[i],这个的意思就是在选第i个物品时,前i-1个物品挑选过的最大价值加上第i个物品的价值(这个时候背包剩余体积需要减去装入第i个物品的体积)。
下面我们来改进代码,如果数据非常大,我们创建二维数组就会出现代码内存太大的错误,我们根据这道题完全可以转换为一个一维数组:但是注意,背包容量的那个for循环只能是从后向前,因为我们必须保证前面的数据对后面的数据不会产生影响。
for(int i=1;i<=N;i++)
for(int j=V;j>0;j--)
{
if(j>=w[i])
s[j]=max(s[j],s[j-w[i]]+v[i]);
else
s[j]=s[j];
}
完整代码:
#include<string.h>
#include<iostream>
using namespace std;
#define MAX_N 1000
#define max(a,b) a>b?a:b
int s[1007];
int main()
{
int T;
cin>>T;
while(T--)
{
int N,V;
cin>>N>>V;
int v[1007],w[1007];
memset(s,0,sizeof(s));
for(int i=1;i<=N;i++)
{
cin>>v[i];
}
for(int i=1;i<=N;i++)
{
cin>>w[i];
}
for(int i=1;i<=N;i++)
for(int j=V;j>0;j--)
{
if(j>=w[i])
s[j]=max(s[j],s[j-w[i]]+v[i]);
else
s[j]=s[j];
}
cout<<s[V]<<endl;
}
}