树上背包问题

5 篇文章 0 订阅

树上背包问题

引例1

金明的预算方案

题意:01背包问题,某些物品有依赖关系,但是一个物品只能依赖一个物品,最多可被两个物品依赖,问你最大价值是多少?

思路:很明显就是01背包的思路,分类讨论就好了
在这里插入图片描述

/*
▄███████▀▀▀▀▀▀███████▄
░▐████▀▒▒▒▒▒▒▒▒▒▒▀██████▄
░███▀▒▒▒ACCEPTED▒▒▒▒▀█████
░▐██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░▐█▌▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░░█▒▄▀▀▀▀▀▄▒▒▄▀▀▀▀▀▄▒▐███▌
░░░▐░░░▄▄░░▌▐░░░▄▄░░▌▐███▌
░▄▀▌░░░▀▀░░▌▐░░░▀▀░░▌▒▀▒█▌
░▌▒▀▄░░░░▄▀▒▒▀▄░░░▄▀▒▒▄▀▒▌
░▀▄▐▒▀▀▀▀▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒█
░░░▀▌▒▄██▄▄▄▄████▄▒▒▒▒█▀
░░░░▄██████████████▒▒▐▌
░░░▀███▀▀████▀█████▀▒▌
░░░░░▌▒▒▒▄▒▒▒▄▒▒▒▒▒▒▐
░░░░░▌▒▒▒▒▀▀▀▒▒▒▒▒▒▒▐

*/

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
const int INF=1e9+7;
const int mod=998244353;
typedef long long ll;
typedef pair<int,int>pi;
int n,V;
int dp[N],cost[N],fa[N],p[N],vis[N];
vector<pi>G[N];
int main() {
    scanf("%d%d",&V,&n);
    for(int i=1; i<=n; i++) {
        scanf("%d%d%d",&cost[i],&p[i],&fa[i]);
        p[i]=p[i]*cost[i];
        G[fa[i]].push_back({cost[i],p[i]});
        vis[i]=fa[i];
    }
    for(int i=1; i<=n; i++) {
        if(vis[i]!=0)
            continue;
        //cout<<i<<" "<<G[i][0].first<<" "<<G[i][1].first<<endl;
        for(int j=V; j>=0; j--) {
            int len=G[i].size();

            if(j>=cost[i])
                dp[j]=max(dp[j],dp[j-cost[i]]+p[i]);
            if(len==0)continue;
            if(j>=cost[i]+G[i][0].first)
                dp[j]=max(dp[j],dp[j-cost[i]-G[i][0].first]+p[i]+G[i][0].second);
            if(len==1)continue;
            if(j>=cost[i]+G[i][1].first)
                dp[j]=max(dp[j],dp[j-cost[i]-G[i][1].first]+p[i]+G[i][1].second);
            if(j>=cost[i]+G[i][1].first+G[i][0].first)
                dp[j]=max(dp[j],dp[j-cost[i]-G[i][1].first-G[i][0].first]+p[i]+G[i][1].second+G[i][0].second);
        }
    }
    cout<<dp[V]<<endl;
}
/*
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
*/

思路2:膜拜其他大佬的思路的时候,看到了这篇题解,感觉思路很好。
在这里插入图片描述
在这里插入图片描述
~~其实很容易想到跑树形dp,在树上很不容易转移,那就把它转移到线性上来,主要就是这个后序遍历不好想…

/*
▄███████▀▀▀▀▀▀███████▄
░▐████▀▒▒▒▒▒▒▒▒▒▒▀██████▄
░███▀▒▒▒ACCEPTED▒▒▒▒▀█████
░▐██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░▐█▌▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░░█▒▄▀▀▀▀▀▄▒▒▄▀▀▀▀▀▄▒▐███▌
░░░▐░░░▄▄░░▌▐░░░▄▄░░▌▐███▌
░▄▀▌░░░▀▀░░▌▐░░░▀▀░░▌▒▀▒█▌
░▌▒▀▄░░░░▄▀▒▒▀▄░░░▄▀▒▒▄▀▒▌
░▀▄▐▒▀▀▀▀▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒█
░░░▀▌▒▄██▄▄▄▄████▄▒▒▒▒█▀
░░░░▄██████████████▒▒▐▌
░░░▀███▀▀████▀█████▀▒▌
░░░░░▌▒▒▒▄▒▒▒▄▒▒▒▒▒▒▐
░░░░░▌▒▒▒▒▀▀▀▒▒▒▒▒▒▒▐

*/

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
const int INF=1e9+7;
const int mod=998244353;
typedef long long ll;
typedef pair<int,int>pi;
int n,V,now;
int dp[65][(int)4e4],cost[N],pre[N];
struct node {
    int v,w;
} t[N],dfn[N];
vector<int>G[N];
void dfs(int u) {
    int tp=now;
    for(auto v:G[u]) {
        dfs(v);
    }
    dfn[++now]=t[u];
    pre[now]=tp;
}
int main() {
    scanf("%d%d",&V,&n);
    for(int i=1; i<=n; i++) {
        int v,w,fa;
        scanf("%d%d%d",&v,&w,&fa);
        w*=v;
        t[i]= {v,w};
        G[fa].push_back(i);
    }
    dfs(0);
    for(int i=1; i<=n; i++) {
        for(int j=0; j<=V; j++) {
            if(j>=dfn[i].v) {
                dp[i][j]=max(dp[pre[i]][j],dp[i-1][j-dfn[i].v]+dfn[i].w);
            } else {
                dp[i][j]=dp[pre[i]][j];
            }
        }
    }
    cout<<dp[n][V]<<endl;
}
/*
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
*/

未完待续…

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值