题目: 有一个容量为m(1<=m<=4000000)的背包,有n(1<=n<=16)个物品,每个物品有体积v(1<=v<=2012)和价值w(0<=2012),现在要你选择一些物品,使得背包所装物品的总价值最大。
Input 有多组测试数据,但是不会超过10组。 对于每组测试数据,第一行是两个整数m和n,表示背包容量的和物品个数。接下来有n行,每行有两个整数,表示一个物品的体积和价值。 输入到文件结束。
Output 对于每组测试数据,输出一行,包含一个整数,为背包能装下物品的最大价值。
Sample Input 10 3 6 9 5 5 5 5 3 2 1 2 2 1 Sample Output 10 3
题目理解: 简单的01背包问题,按照动态规划的思路,首先定义两个变量N,S,分别存放物品个数和总的背包可容纳体积,另外定义两个数组,分别保存各个物品的体积和价值,另外定义一个dp[]数组,可存放dp动态表(很美的~可在需要的时候打印出来,方便理解),最后输出dp[N][S]。但这里要特别注意的坑是,如果你按照题目所给的背包最大体积-4000000来申请空间,那么抱歉,后面无论你怎么尝试都会告诉你‘Memory Limit Exceeded’的字样,也就是空间申请的太大了,我第一遍写的时候就按照题目所给的限制申请数组,所用空间为266088kB,而题目上给的仅仅是10240 kB,这差了相当于26倍,所以,这里需要对空间进行优化。仔细一瞅,题目上告诉我们每个物品最大为2012体积单位,而最多只有16个物体,所以你只需要申请16*2012的空间就可以了,这样差不多34000就足够了,缩小了100多倍。
#include<iostream>
#include<cstdio>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<deque>
#include<vector>
#include<queue>
#include<string>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<iomanip>
#define ll long long
using namespace std;
int N,S;
int dp[17][33000];
int w[17]={0};
int v[17]={0};
void findmax()
{
for(int i=1;i<=N;i++)
{
for(int j=1;j<=S;j++)
{
if(j<w[i])
dp[i][j]=dp[i-1][j];
else
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
}
}
}
int main()
{
while(cin>>S>>N)
{
int sum1=0,sum2=0;
memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++)
{
cin>>w[i]>>v[i];
sum1+=w[i];
sum2+=v[i];
}
if(sum1<S)///注意自己输入的是m,即使合在一起的体积没那么大,容积还是会在遍历时用到m的数值,而发生数组越界,因此注意
{
printf("%d\n",sum2);///当输入的容积大于总体积时,可以直接输出所有的价值和,不用一个一个装上去了
continue;
}
findmax();
cout<<dp[N][S]<<endl;
}
return 0;
}