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 }
原文地址:https://www.cnblogs.com/Misaki-Mei/p/7623893.html