题意
金明有n元钱,最多允许购买m件物品。物品分为两类:主件和附件。规定:每个主件有0、1或2个附件,每个附件只对应一个主件,附件没有自己的附件。给出每件物品的价格,重要度,和从属关系,求出所选物品的价格与重要度乘积最大值。
题目分析
这是一道有依赖的背包问题。
仅考虑一个主件和它的附件集合,可选的策略最多有以下五种:
- 不选
- 仅选主件 — 物品1
- 选主件+附件1 — 物品2
- 选主件+附件2 — 物品3
- 选主件+附件1+附加2 — 物品4
问题转化成了分组背包,每组中最多有4种物品,组内的物品相互冲突。则按照分组背包的策略解决问题:枚举每个组,选组内的某件物品或都不选。
【数据存储】
int dp[maxn];
int v[maxm][5]; //v[][0]~v[][3] 分别存物品1-4
int vw[maxm][5]; //由于题目是要求∑v*w 最大值,因此直接预处理乘积作为”价值“
【预处理】
memset(v,-1,sizeof(v));
cin>>n>>m;
for(int i = 1;i<=m;i++){
int a,b,c;
scanf("%d%d%d", &a,&b,&c);
if(c == 0) {//主件
v[i][0] = a,vw[i][0] = a*b; // -- 物品1
}else{ //附件
if(v[c][1] == -1) { //第1个附件
v[c][1] = a + v[c][0], vw[c][1] = a*b + vw[c][0]; // -- 物品2
}else{ //第2个附件
v[c][2] = a + v[c][0], vw[c][2] = a*b + vw[c][0]; // -- 物品3
v[c][3] = v[c][2] + v[c][1] - v[c][0], vw[c][3] = vw[c][2] + vw[c][1] - vw[c][0] ; // -- 物品4
}
}
}
【分组背包处理】
int cal(){
for(int i = 1;i<=m;i++){
if(v[i][0] == -1) continue;
for(int j = n;j>=0;j--){
for(int k = 0;v[i][k] != -1;k++){ //枚举组内每个物品
if(j-v[i][k]>=0)
dp[j] = max(dp[j], dp[j-v[i][k]] + vw[i][k]);
}
}
}
return dp[n];
}