题目大意:
购物,买相应物品之前必须先买能装相应物品的盒子,现在已知n个盒子的价钱,以及每个盒子能装的物品数,以及这些物品的价值和花费。为w钱下能买到物品的最大价值。
思路:背包。首先很容易想到的一个状态转移方程是:
DP[i][j]=MAX{DP[i-1][j],MAX{DP[i-1][j-k]+Pack[i][k]}}。其中
DP[i][j]表示前i个盒子中,在金钱j下所能得到的最大价值。考虑第i个盒子选和不选,以及选的话分配多少钱给i。
然而很明显上述时间复杂度过高。考虑优化。仔细分析,会发现MAX{DP[i-1][j-k]+Pack[i][k]},
实际上表示的是在金钱j下且一定考虑第i个盒子下的最大价值。将盒子的价值看作0,在金钱j下首先将盒子的价钱考虑进去。那么剩下的只是挑选i盒子中的物品,即01背包。令f(i,j)为前i个盒子中且第i个盒子必须考虑时在金钱j下的
所得最大价值。那么该初始值f(i,j)=DP[i-1][j-Pbox[i]]+0;初始值确定以后(相当于已经忽略了盒子的影响)。那么直接背包即可。
——————转载
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define M 100001
int dp[51][M],n;
int main()
{
int n,v;
while(scanf("%d%d",&n,&v)!=EOF){
memset(dp,-1,sizeof dp);
memset(dp[0],0,sizeof dp[0]);
for(int i=1;i<=n;++i){
int x,p;
scanf("%d%d",&x,&p);
for(int j=x;j<=v;++j) dp[i][j]=dp[i-1][j-x];
while(p--){
int c,w;
scanf("%d%d",&c,&w);
for(int j=v;j>=c;--j){
if(dp[i][j-c]!=-1){
dp[i][j]=max(dp[i][j],dp[i][j-c]+w);
}
}
}
for(int j=0;j<=v;++j){
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
}
cout<<dp[n][v]<<endl;
}
return 0;
}