题意:买附件的前提是买了主件,问给定金额获得的最大价值。
分析:有依赖的背包模板题,注意有依赖的背包不是分组背包的那种三个for的顺序,而是枚举一个主件后,不断的枚举附件,而购买多个不同的附件。
同时,在写法上,用 f 数组表示答案数组,f 的每个 j 都是对应最优的决策,而每次枚举都在 t 数组上操作,再判断f 数组上哪些需要更新。
*分组背包是将物品分组,每组的物品相互冲突,最多只能选一个物品放进去。其实是从“在所有物品中选择一件”变成了“从当前组中选择一件”,于是就对每一组进行一次 0-1 背包就可以了。
*分组背包核心代码:
for (int k = 1; k <= ts; k++) //循环每一组 for (int i = m; i >= 0; i--) //循环背包容量 for (int j = 1; j <= cnt[k]; j++) //循环该组的每一个物品 if (i >= w[t[k][j]]) dp[i] = max(dp[i], dp[i - w[t[k][j]]] + c[t[k][j]]); //像0-1背包一样状态转移 ,像0-1背包一样的防止重复放进同一物品的思路
本题代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; const int maxn = 202003; struct node{ int p,v,f; }a[777]; int f[maxn]; int t[maxn]; int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1; i<=m; i++){ scanf("%d%d%d",&a[i].p,&a[i].v,&a[i].f); a[i].v *= a[i].p; } for(int i=1; i<=m; i++){ //一步 if(!a[i].f){ for(int j=0; j<a[i].p; j++){ t[j] = f[j]; } for(int j=a[i].p; j<=n; j++){ t[j] = f[j - a[i].p]+a[i].v; } for(int k=1; k<=m; k++){ //两步 if(a[k].f==i){ for(int j=n; j>=a[i].p; j--){ //三步 (注意这不是多组背包的写法,可以放进同一组的物品) if(j-a[k].p>=a[i].p){ // printf("yes "); t[j] = max(t[j-a[k].p]+a[k].v , t[j]); // printf("%d %d ", j, t[j]); } } } } for(int j=a[i].p; j<=n; j++){ f[j] = max(f[j],t[j]); } } } printf("%d ", f[n]); }