[有依赖的背包问题] 金明的预算方案 P1064 洛谷

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值