【动态规划】AcWing10. ThereAreDependencyKnapsackIssues-有依赖的背包问题

背包九讲:
01背包问题
完全背包问题
多重背包问题I
多重背包问题II
混合背包问题
二维费用的背包问题
分组背包问题
有依赖的背包问题
背包问题求方案数
背包问题求具体方案
ps:建议从前向后刷哦~

🔗原题

有依赖的背包问题

有 N 个物品和一个容量是 V 的背包。
物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式
第一行有两个整数 N,V,用空格隔开,分别表示物品个数和背包容量。
接下来有 N 行数据,每行数据表示一个物品。
第 i 行有三个整数 vi,wi,pi,用空格隔开,分别表示物品的体积、价值和依赖的物品编号。
如果 pi=−1,表示根节点。 数据保证所有物品构成一棵树。
输出格式
输出一个整数,表示最大价值。

数据范围
1≤N,V≤100
1≤vi,wi≤100
父节点编号范围:
内部结点:1≤pi≤N;
根节点 pi=−1;

输入样例
5 7
2 3 -1
2 2 1
3 5 1
4 7 2
3 6 2
输出样例:
11

题解

某个节点在选择别的节点的内容时候只能在一个节点中所有体积可能中选取一个,所以为分组背包问题,又因为这个背包依赖呈树状的,先深度优先该树,每个节点都可以当一个根结点,然后算得各体积情况下的最大值,最后一个主要的根结点的最大体积包括的就是最优解
状态转移公式为
dp[节点][体积] = Math.max(dp[节点][体积], dp[节点][体积 - 子节点体积] + dp[子节点][子节点体积])

代码

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    static int N, V, root;
    static int[][] dp;
    static class bag{
        int v, w;
        ArrayList<Integer> list;
        bag() {
            this.list = new ArrayList<>();
            list.add(0);
        }
    }
    public static bag[] b;
    public static void dfs(int x) {
        for(int i = b[x].v; i <= V; i++) dp[x][i] = b[x].w;
        for(int i = 1; i < b[x].list.size(); i++) {
            int u = b[x].list.get(i);
            dfs(u);
            for(int j = V; j >= b[x].v; j--) {
                for(int k = 0; k <= j - b[x].v; k++) {
                    dp[x][j] = Math.max(dp[x][j], dp[x][j - k] + dp[u][k]);
                }
            }
        }
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        V = sc.nextInt();
        b = new bag[N + 1];
        dp = new int[N + 1][V + 1];
        for(int i = 0; i <= N; i++) b[i] = new bag();
        for(int i = 1; i <= N; i++) {
            int p;
            b[i].v = sc.nextInt();
            b[i].w = sc.nextInt();
            p = sc.nextInt();
            if(p == -1) root = i;
            else b[p].list.add(i);
        }
        dfs(root);
        System.out.println(dp[root][V]);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值