LeetCode笔记---树型DP入门

这篇博客介绍了如何使用树形动态规划解决一个关于寻找没有上司的舞会中,最大快乐指数的问题。代码示例展示了如何通过递归遍历树结构,计算每个节点的最大快乐指数,最后找到全局最优解。此外,还提到了类似的LeetCode题目337.打家劫舍III,该题目可以通过类似的方法解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

更多看这里吧😁

这应该是一道最经典的树型DP入门题了,我学习了一下。

285. 没有上司的舞会

Ural 大学有 N 名职员,编号为 1∼N。

他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司。

每个职员有一个快乐指数,用整数 Hi 给出,其中 1≤i≤N。

现在要召开一场周年庆宴会,不过,没有职员愿意和直接上司一起参会。

在满足这个条件的前提下,主办方希望邀请一部分职员参会,使得所有参会职员的快乐指数总和最大,求这个最大值。

输入格式 第一行一个整数 N。

接下来 N 行,第 i 行表示 i 号职员的快乐指数 Hi。

接下来 N−1 行,每行输入一对整数 L,K,表示 K 是 L 的直接上司。

输出格式 输出最大的快乐指数。

数据范围 1≤N≤6000, −128≤Hi≤127
输入样例: 7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5
输出样例: 5

在这里插入图片描述

(下面代码的dp[x][0] 代表的是该节点的参加,1是不参加)

import java.util.Scanner;
import java.util.*;

public class Main {
    
    static int[] h = new int[6001];
    
    static int[][] v = new int[6001][6001];
    
    static Scanner scan = new Scanner(System.in);
    
    static int[][] dp = new int[6001][2];
    
    public static void main(String[] args) {
        int N = Integer.valueOf(scan.nextLine());
        int t = N;
        for (int i = 0; i < N; i++) {
            h[i + 1] = Integer.valueOf(scan.nextLine());
        }
        for (int i = 0; i < N - 1; i++) {
            String[] split = scan.nextLine().split(" ");
            int l = Integer.valueOf(split[0]);
            int k = Integer.valueOf(split[1]);
            List<Integer> son = v.getOrDefault(k, new ArrayList<>());
            son.add(l);
            v.put(k, son);
            v[k][]
        } 
        int p = findPar(N);
        dfs(p);
        System.out.println(Math.max(dp[p][1], dp[p][0]));
    }
    
    private static void dfs(int p) {
        dp[p][0] = h[p];
        dp[p][1] = 0;
        List<Integer> son = v.get(p);
        if (son == null) {
            return;
        }
        for (Integer s: son) {
            dfs(s);
            dp[p][1] += Math.max(dp[s][0], dp[s][1]);
            dp[p][0] += dp[s][1];
        }
    }
    
    private static int findPar(int N) {
        int[] vis = new int[N + 1];
        for (Integer k: v.keySet()) {
            List<Integer> son = v.get(k);
            for (Integer s: son) {
                vis[s] = 1;
            }
        }
        for (int i = 1; i <= N; i++) {
            if (vis[i] == 0) {
                return i;
            }
        }
        return 1;
    }
}

此外,LeetCode上还有一题一摸一样的,非常简单的入门题,调用个API就好了。

337. 打家劫舍 III
在这里插入图片描述
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {

    HashMap<TreeNode, int[]> f = new HashMap<>(256);

    public int rob(TreeNode root) {
        dfs(root);
        return Math.max(f.get(root)[0], f.get(root)[1]);
    }

    private void dfs(TreeNode root) {
        if (root == null) {
            return;
        }
        int[] s = new int[] {0, root.val};
        f.put(root, s);
        dfs(root.left);
        if (root.left != null) {
            int[] sl = f.get(root.left);
            s[0] += Math.max(sl[0], sl[1]);
            s[1] += sl[0];
        }
        dfs(root.right);
        if (root.right != null) {
            int[] sr = f.get(root.right);
            s[0] += Math.max(sr[0], sr[1]);
            s[1] += sr[0];
        }
    }
}

时间复杂度O(n)
空间复杂度O(n)


更多看这里吧😁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值