洛谷 P1064 金明的预算方案(01背包问题)
https://www.cnblogs.com/violet-acmer/p/9852294.html
题解:
这道题是 “01”背包问题的变形。
如果不考虑买附件必须买相应的主件这一条件下,这就是单纯的 “01”背包问题。
那,这道题该如何做呢?
注意看一下题干,每个主件最多有 2 个附件,那这就容易些了,枚举所有的可能;
对于第 i 个主件,有以下五种可能:
(1):不选主件 i
(2):只选主件 i
(3):选主件 i + 附件1
(4):选主件 i + 附件2
(5):选主件 i + 附件1 + 附件2
从这五个中找到最大的价值组合,并和 dp[i-1][ j ]判断,取最大值,当然在选择附件时,需要满足当前价值可以容下所选择的总价值。
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 #define P pair<int ,int > 5 const int maxn=3.2e4+50; 6 7 int n,m; 8 int dp[70][maxn]; 9 P mainG[maxn];//存储主件信息 10 P touchG[70][maxn];//touchG[i] : 存储主件 i 含有的附件信息 11 int total[70];//total[i] : 主件 i 含有的附件个数 12 int Val(P p){ 13 return p.first*p.second; 14 } 15 void Solve() 16 { 17 for(int i=1;i <= m;++i) 18 { 19 P one=touchG[i][1]; 20 P two=touchG[i][2]; 21 for(int j=1;j <= n;++j) 22 { 23 dp[i][j]=dp[i-1][j]; 24 if(j >= mainG[i].first) 25 dp[i][j]=max(dp[i][j],dp[i-1][j-mainG[i].first]+Val(mainG[i])); 26 if(j >= mainG[i].first+one.first) 27 dp[i][j]=max(dp[i][j],dp[i-1][j-mainG[i].first-one.first]+Val(mainG[i])+Val(one)); 28 if(j >= mainG[i].first+two.first) 29 dp[i][j]=max(dp[i][j],dp[i-1][j-mainG[i].first-two.first]+Val(mainG[i])+Val(two)); 30 if(j >= mainG[i].first+one.first+two.first) 31 dp[i][j]=max(dp[i][j],dp[i-1][j-mainG[i].first-one.first-two.first]+Val(mainG[i])+Val(one)+Val(two)); 32 } 33 } 34 printf("%d\n",dp[m][n]); 35 } 36 int main() 37 { 38 scanf("%d%d",&n,&m); 39 for(int i=1;i <= m;++i) 40 { 41 int v,p,q; 42 scanf("%d%d%d",&v,&p,&q); 43 if(!q) 44 mainG[i]=P(v,p); 45 else 46 touchG[q][++total[q]]=P(v,p); 47 } 48 Solve(); 49 }
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 #define P pair<int ,int > 5 const int maxn=3.2e4+50; 6 7 int n,m; 8 int dp[maxn]; 9 P mainG[maxn];//存储主件信息 10 P touchG[70][maxn];//touchG[i] : 存储主件 i 含有的附件信息 11 int total[70];//total[i] : 主件 i 含有的附件个数 12 int Val(P p){ 13 return p.first*p.second; 14 } 15 void Solve() 16 { 17 for(int i=1;i <= m;++i) 18 { 19 P one=touchG[i][1]; 20 P two=touchG[i][2]; 21 for(int j=n;mainG[i].first != 0 && j >= 1;--j) 22 { 23 if(j >= mainG[i].first) 24 dp[j]=max(dp[j],dp[j-mainG[i].first]+Val(mainG[i])); 25 if(j >= mainG[i].first+one.first) 26 dp[j]=max(dp[j],dp[j-mainG[i].first-one.first]+Val(mainG[i])+Val(one)); 27 if(j >= mainG[i].first+two.first) 28 dp[j]=max(dp[j],dp[j-mainG[i].first-two.first]+Val(mainG[i])+Val(two)); 29 if(j >= mainG[i].first+one.first+two.first) 30 dp[j]=max(dp[j],dp[j-mainG[i].first-one.first-two.first]+Val(mainG[i])+Val(one)+Val(two)); 31 } 32 } 33 printf("%d\n",dp[n]); 34 } 35 int main() 36 { 37 scanf("%d%d",&n,&m); 38 for(int i=1;i <= m;++i) 39 { 40 int v,p,q; 41 scanf("%d%d%d",&v,&p,&q); 42 if(!q) 43 mainG[i]=P(v,p); 44 else 45 touchG[q][++total[q]]=P(v,p); 46 } 47 Solve(); 48 }
关于主件编号问题(踩坑了):
m个物品,编号为 1~m,而不是按照主件的个数进行编号。
例如:
(正确编号)(错误编号)
2000 10
500 1 0 1 1
400 4 0 2 2
300 5 1 3
400 5 1 4
200 5 0 5 3
500 4 5 6
400 4 0 7 4
320 2 0 8 5
410 3 0 9 6
400 3 5 10
找这个BUG找了好几个小时,mmp,心累啊.................