(金明的预算方案)依赖性的背包
例题的话,可以看一下洛谷1064 金明的预算方案
原题链接 https://www.luogu.org/problemnew/show/P1064
有依赖性的背包,顾名思义,及选中其中一个物品,另一个物品必须随之选择
题意:
有n个物品,预算为V元,w[i]为每个物品的价格,v[i]为每个物品的重要程度,c[i]为每个数的主件,
如果c[i]为0,则代表该物品为主件,否则为c[i]的附件,每个物品的价值为w[i]*v[i],求最大的价值。
这就是典型的依赖性背包,我们可以首先可以用01背包的思想预处理出4种情况
1.只选择主件
2.选择主件且选择附件1
3.选择主件且选择附件2
4选择主件且选择附件1和附件2
这就是一个01背包,题目中保证每个主件只有两个附件,所以讲处理过的放入vector中,
接下来就是分组背包,因为选择了其中一种情况是不可能在选择其他的情况的
这题就可以a掉了
注意!!!
1.在预处理时不要忘了把主件加进去。
2.预处理出来如果一种情况与另一种情况的价值一样,则价格小的一定是最优的,见代码注释
#include <cstdio> #include <cstdlib> #include <vector> #include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N=60; struct node { int w,v; node(int ww,int vv) { w=ww,v=vv; } }; vector <node> g[N],g1[N]; int n,V,v[N],w[N],c[N],dp[200005]; int main() { scanf("%d %d",&V,&n); for(int i=1;i<=n;i++) { scanf("%d %d %d",&w[i],&v[i],&c[i]); v[i]=v[i]*w[i]; if(c[i]) g[c[i]].push_back(node(w[i],v[i])); } for(int i=1;i<=n;i++) { if(!g[i].empty()) { memset(dp,0,sizeof(dp)); for(int k=0;k<g[i].size();k++) { for(int j=V-w[i];j>=g[i][k].w;j--) { dp[j]=max(dp[j],dp[j-g[i][k].w]+g[i][k].v);//01背包 } } for(int j=1;j<=V-w[i];j++) { if(dp[j] && dp[j-1]!=dp[j])//此处为注意的第二点 g1[i].push_back(node(w[i]+j,dp[j]+v[i])); } g1[i].push_back(node(w[i],v[i])); //此处为注意的第一点 } else if(!c[i]) { g1[i].push_back(node(w[i],v[i]));//此处也为注意的第一点 } } memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++)//分组背包 { for(int j=V;j>=0;j--) { for(int k=0;k<g1[i].size();k++) { if(j>=g1[i][k].w) dp[j]=max(dp[j],dp[j-g1[i][k].w]+g1[i][k].v); } } } printf("%d\n",dp[V]); return 0; }
我居然写了两个小时,还是我太蒻了