P1064 金明的预算方案 (背包)

题目链接

 

 

 

 

题解:

对每种主件的 附件的集合 进行一次 01 背包处理,就可以先求出 对于每一种主件包括其附件的组合中,每种花费的最大价值,对应不同的方案。

在对主件进行背包处理。

需要注意的是在对每个主件的附件进行处理时,要恰好花完价钱,否则方案数会非常多。

Code:

 1 #include <bits/stdc++.h>
 2 # define LL long long
 3 using namespace std;
 4 
 5 const int maxn=65;
 6 int N, m;
 7 
 8 struct Obj{
 9     int v,p,q;
10 }arr[maxn];;
11 Obj fujian[maxn][5]; //主件的附件信息
12 int fcnt[maxn];  //主件的附件个数
13 int f[33000];    //i价钱取得的最大价值
14 int V[maxn][5];   //主件的不同方案需要的价钱
15 int P[maxn][5];   //主件的不同方案获得的价值
16 int pcnt[maxn];   //各个主件的方案数
17 
18 int main(){
19     scanf("%d %d", &N, &m);
20     int a,b,c;
21     for(int i=1;i<=m;++i){
22         scanf("%d %d %d", &a, &b, &c);
23         arr[i].v=a;
24         arr[i].p=b;
25         arr[i].q=c;
26         if(c>0){
27             fcnt[c]++;
28             fujian[c][fcnt[c]].v=a;
29             fujian[c][fcnt[c]].p=b;
30             fujian[c][fcnt[c]].q=c;
31         }
32     }
33     for(int i=1;i<=m;++i){   //处理主件及其相应附件
34         if(arr[i].q==0){
35             //只取主件
36             ++pcnt[i];
37             V[i][pcnt[i]]=arr[i].v;
38             P[i][pcnt[i]]=arr[i].v*arr[i].p;
39 
40             //考虑取不同附件
41             memset(f,-1,sizeof(f));
42             f[0]=0;
43             for(int j=1;j<=fcnt[i];++j){
44                 for(int k=N-arr[i].v;k>=fujian[i][j].v;--k){
45                     if(f[k-fujian[i][j].v]!=-1)
46                         f[k]=max(f[k],f[k-fujian[i][j].v]+fujian[i][j].v*fujian[i][j].p);
47                 }
48             }
49 
50             for(int j=0;j<=N-arr[i].v;++j){  //不同价钱对应的价值,即不同的方案
51                 if(f[j]!=-1){
52                     ++pcnt[i];
53                     V[i][pcnt[i]]=arr[i].v+j;
54                     P[i][pcnt[i]]=arr[i].v*arr[i].p+f[j];
55                 }
56             }
57         }
58     }
59     memset(f,0,sizeof(f));
60     for(int i=1;i<=m;++i){
61         if(arr[i].q==0){
62             for(int j=N;j>=arr[i].v;--j){
63                 for(int k=1;k<=pcnt[i];++k){
64                     if(j>=V[i][k]){
65                         f[j]=max(f[j],f[j-V[i][k]]+P[i][k]);
66                     }
67                 }
68             }
69         }
70     }
71     printf("%d", f[N]);
72     return 0;
73 }

 

 

注意到题目说只有三种情况,每个主件可以有0个、1个或2个附件。

所以可以这样写:

 

 1 #include <bits/stdc++.h>
 2 # define LL long long
 3 using namespace std;
 4 
 5 const int maxn=65;
 6 int N, m;
 7 
 8 struct Obj{
 9     int v,p,q;
10 }arr[maxn];;
11 Obj fujian[maxn][5]; //主件的附件信息
12 int fcnt[maxn];  //主件的附件个数
13 int f[33000];    //i价钱取得的最大价值
14 int V[maxn][5];   //主件的不同方案需要的价钱
15 int P[maxn][5];   //主件的不同方案获得的价值
16 int pcnt[maxn];   //各个主件的方案数
17 
18 int main(){
19     scanf("%d %d", &N, &m);
20     int a,b,c;
21     for(int i=1;i<=m;++i){
22         scanf("%d %d %d", &a, &b, &c);
23         arr[i].v=a;
24         arr[i].p=b;
25         arr[i].q=c;
26         if(c>0){
27             fcnt[c]++;
28             fujian[c][fcnt[c]].v=a;
29             fujian[c][fcnt[c]].p=b;
30             fujian[c][fcnt[c]].q=c;
31         }
32     }
33     
34     for(int i=1;i<=m;++i){
35         if(arr[i].q==0){
36             for(int j=N;j>=arr[i].v;--j){
37                 f[j]=max(f[j],f[j-arr[i].v]+arr[i].v*arr[i].p);
38 
39                 if(fcnt[i]>0 && j-arr[i].v-fujian[i][1].v>=0){
40                     f[j]=max(f[j],f[j-arr[i].v-fujian[i][1].v]+arr[i].v*arr[i].p+fujian[i][1].v*fujian[i][1].p);
41                 }
42                 if(fcnt[i]>1 && j-arr[i].v-fujian[i][2].v>=0){
43                     f[j]=max(f[j],f[j-arr[i].v-fujian[i][2].v]+arr[i].v*arr[i].p+fujian[i][2].v*fujian[i][2].p);
44 
45                     if(j-arr[i].v-fujian[i][2].v-fujian[i][1].v>=0){
46                         f[j]=max(f[j],f[j-arr[i].v-fujian[i][2].v-fujian[i][1].v]+arr[i].v*arr[i].p+fujian[i][2].v*fujian[i][2].p
47                         +fujian[i][1].v*fujian[i][1].p);
48                     }
49                 }
50             }
51         }
52     }
53     printf("%d", f[N]);
54     return 0;
55 }

 

posted @ 2020-02-01 17:59  feibilun  阅读(126)  评论(0编辑  收藏  举报