DP——背包问题(三)
终于到了有附带条件的背包问题了,现在讲一个很简单的带有主件、附件的问题的背包问题的解法……这道题我一直拖了一年都没有写……
题意:
有m件物品,其中有主件,有附件,每个主件的附件最多2个,只有选了主件才能选附件,不能单独选附件。每件物品有重要性和需要花费的钱数,他的价值是重要性和需要花费的钱数的积……现在有n元钱,要求买到的物品价值之和最大。
输入格式:
输入的第1行,为两个正整数,用一个空格隔开:
N m (其中N(<32000)表示总钱数,m(<60)为希望购买物品的个数。)
从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数
v p q (其中v表示该物品的价格(v<10000),p表示该物品的重要度(1~5),q表示该物品是主件还是附件。如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号)
输出格式:
输出只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000)。
对于这道题的物品可以进行以下处理:
首先,将所有主件挑出来,主件就最多有4种选择:只要主件;要主件和一号附件;要主件和二号附件;要主件和一号和二号附件;
这样一来,就相当于把问题从“选”与“不选”转化为“选哪种方案”,在利用01背包,就能快速求解;
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 using namespace std; 8 9 int dp[600000],n,m,w,ge,pp,ppp; 10 int fn[1000][1000][2]; 11 int fnn[1000]; 12 int v[1000],cun[100]; 13 struct ez{ 14 int vy; 15 int w; 16 int p; 17 } a[100]; 18 19 int main(){ 20 scanf("%d %d",&n,&m); 21 n=n/10; 22 for(int i=1;i<=m;i++) scanf("%d %d %d",&a[i].w,&a[i].vy,&a[i].p); 23 for(int i=1;i<=m;i++){ 24 a[i].w/=10; 25 if(a[i].p==0){ 26 ge++; 27 cun[i]=ge; 28 fnn[ge]++; 29 fn[ge][fnn[ge]][0]=a[i].vy*a[i].w; 30 fn[ge][fnn[ge]][1]=a[i].w; 31 }else{ 32 ppp=fnn[cun[a[i].p]]; 33 while(fnn[cun[a[i].p]]-ppp+1<=ppp){ 34 fnn[cun[a[i].p]]++; 35 fn[cun[a[i].p]][fnn[cun[a[i].p]]][1]=fn[cun[a[i].p]][fnn[cun[a[i].p]]-ppp][1]+a[i].w; 36 fn[cun[a[i].p]][fnn[cun[a[i].p]]][0]=fn[cun[a[i].p]][fnn[cun[a[i].p]]-ppp][0]+a[i].vy*a[i].w; 37 } 38 } 39 } 40 for(int i=1;i<=ge;i++) 41 for(int j=n;j>=1;j--) 42 for(int k=1;k<=fnn[i];k++){ 43 if(j>=fn[i][k][1]) dp[j]=max(dp[j],dp[j-fn[i][k][1]]+fn[i][k][0]); 44 } 45 cout<<dp[n]*10<<endl; 46 return 0; 47 }