金明的预算方案
Description
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的。
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
Analysis
第一次遇到的依赖性背包问题。
如果取消附件的限制,那么这题可以用01背包解决。加上附件之后,相当于1个主件变成了4件物品(附件的选择导致),且此4件物品互相冲突。因为4常数非常小..所以在计算到此主件组时,只要枚举4种情况,找出最优情况就行了。
但是如果附件变多了,组合数太多,为2^n,该怎么办呢?不难发现主件组中各种组合进行了多次冗余计算,可以想到先给主件组中的组合来一发01背包,求出各种价格下的最大获得值,这样就把所有的组合化成了价格数个物品。当然这题无需优化。
Code
#include <bits/stdc++.h>
int n,m,dp[32001],id[101];
std::vector <int> gift[101];
struct node{
int v,w;
}th[101];
int main(){
freopen("budget.in","r",stdin);
freopen("budget.ans","w",stdout);
std::cin>>n>>m;
for(int i=1;i<=m;i++){
int q;
std::cin>>th[i].v>>th[i].w>>q;
th[i].w*=th[i].v;
if(!q)id[++id[0]]=i;
else gift[q].push_back(i);
}
m=id[0];
for(int i=1;i<=m;i++)
for(int j=n;j>=th[id[i]].v;j--){
int v=th[id[i]].v;
int w=th[id[i]].w;
dp[j]=std::max(dp[j],dp[j-v]+w);
if(gift[id[i]].empty())continue;
for(int k=0;k<gift[id[i]].size();k++){
int s=gift[id[i]][k];
if(j>=th[s].v+v)
dp[j]=std::max(dp[j],dp[j-v-th[s].v]+w+th[s].w);
}
if(gift[id[i]].size()>1){
int s0=gift[id[i]][0];
int s1=gift[id[i]][1];
if(j>=th[s0].v+th[s1].v+v)
dp[j]=std::max(dp[j],dp[j-v-th[s0].v-th[s1].v]+w+th[s0].w+th[s1].w);
}
}
std::cout<<dp[n]<<std::endl;
return 0;
}