存疑:第一种代码为何WA?
思路:
- 注意题面没说多组用例,但是实际上是,很坑。
- 依赖背包,即每组中的物品由一个主件和若干附件组成,若买任意附件则必须先买主件。本题中主件价值为零,价格倒是挺贵。
- 首先按照背包九讲中的做法,不知为何WA:对每一组中的物品先进行一次Sub_Pack(详见背包九讲)。再对物品进行Main_Pack。(均为01Pack)
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MIN 0xc0c0c0c0
using namespace std;
const int maxw = 100005;
const int sub_maxw = 2005;
const int maxn = 15;
int num,W;
int dp[maxw];
int sub_dp[sub_maxw];
int w[maxn];
int v[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>num>>W){
memset(dp,0,sizeof(dp));
for(int k=1;k<=num;k++){
int p,n;
cin>>p>>n;
for(int i=1;i<=n;i++)
cin>>w[i]>>v[i];
memset(sub_dp,MIN,sizeof(sub_dp));
sub_dp[0] = 0;
for(int i=1;i<=n;i++){
for(int j = sub_maxw - 1 ; j >= w[i] ; j--){
sub_dp[j] = max(sub_dp[j] , sub_dp[j - w[i]] + v[i]);
}
}
for(int j = sub_maxw-1 ; j >= p ; j--)
sub_dp[j] = sub_dp[j - p];
for(int i = p ; i < sub_maxw ; i++){
if(sub_dp[i] <= 0)
continue;
for(int j=W;j>=i;j--)
dp[j] = max(dp[j] , dp[j-i] + sub_dp[i]);
}
}
cout<<dp[W]<<endl;
}
return 0;
}
思路:
- 此路不通,考虑在处理每组物品之前,使用一个主dp数组的复制品sub_dp,然后对本组物品在sub_dp中直接01Pack。Pack之后再通过串格的方式加入盒子的价钱。注意可能会有从未买本组物品的格子它们的代价也被加上了一个盒子的价钱,但是这在判断是否采用新格子的时候就被消除了不良影响。
- 注意这种方法sub_dp数组的大小要迁就dp数组。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MIN 0xc0c0c0c0
using namespace std;
const int maxw = 100005;
const int maxn = 15;
int num,W;
int dp[maxw];
int sub_dp[maxw];
int w[maxn];
int v[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>num>>W){
memset(dp,0,sizeof(dp));
for(int k=1;k<=num;k++){
int p,n;
cin>>p>>n;
for(int i=1;i<=n;i++)
cin>>w[i]>>v[i];
memcpy(sub_dp,dp,sizeof(dp));
for(int i=1;i<=n;i++){
for(int j=W;j>=w[i];j--){
sub_dp[j] = max(sub_dp[j] , sub_dp[j - w[i]] + v[i]);
}
}
for(int j = W ; j >= p ; j--)
sub_dp[j] = sub_dp[j - p];
for(int i=p;i<=W;i++)
dp[i] = max(dp[i] , sub_dp[i]);
}
cout<<dp[W]<<endl;
}
return 0;
}