https://www.luogu.org/problemnew/solution/P1064
有依赖背包的入门题 除了树形DP 就是这了
非树形有依赖的背包问题(只有两类物品:主件,附件)有主件才可以选附件
首先我们注意到对于每一个主件,有很多种购买的方案:可以不买,可以只买主件,或者买主件外加几种附件,当附件个数较少的时候枚举就可以过
但我们正解的话,可以先对每种主件的 附件的集合 进行一次 01 背包处理,就可以先求出 对于每一种主件包括其附件的组合中,每种花费的最大价值
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <list>
using namespace std;
typedef long long ll;
const int maxn = 100+5 ;
const int maxv = 32000+5;
const int mod = 1000000 ;
const int INF = 0x3f3f3f3f;
const double PI=acos(-1.0);
int n,m,d,x,y,flag;
int v,p,q;
pair<int,int>w[maxn]; // 存只出现一次主件没有配件的
vector<pair<int,int> >groups[maxn]; // 处理完放这里 然后DP
int dp[maxv];
int main(){
scanf("%d %d",&n,&m);
for(int i=0;i<=m;i++) groups[i].push_back(make_pair(0,0));// 初始化第一个是0用来只放主件
for(int i=1;i<=m;i++){ //之后第一次放这里的就是只选主件的价值和容量
scanf("%d %d %d",&v,&p,&q);
if(q==0){
w[i].first=v;w[i].second=p*v;
}else{
int len=groups[q].size(); // 先录入附件
for(int j=0;j<len;j++){ // 之后再录入他的附件就会遍历这里
int cost=groups[q][j].first+v; //选第一个第二个
int val=groups[q][j].second+p*v; //或者和之前已经组合的 1和附件 在组合 放到这层vector后
groups[q].push_back(make_pair(cost,val));
}
}
}
for(int i=1;i<=m;i++){ // 这里吧主件价格和容量 补进去
for(int j=0;j<groups[i].size()&&w[i].first;j++){
groups[i][j].first+=w[i].first;
groups[i][j].second+=w[i].second;
}
}
for(int i=1;i<=m;i++){ // 01背包 先dp 组合
for(int j=n;j>=0&&groups[i].size();j--){ // 组合内在01背包
for(int k=0;k<groups[i].size();k++){
if(j>=groups[i][k].first){
dp[j]=max(dp[j],dp[j-groups[i][k].first]+groups[i][k].second);
}
}// 在j价格下 然后 i 组合 第k类下处理完 最大值
}
}
printf("%d\n",dp[n]);
return 0;
}