记一道有趣的题目

本文探讨了一道有趣的算法题目,旨在通过优化派对邀请策略,最大化整体快乐值。问题背景设定在一个公司的人力资源结构上,采用多叉树表示员工关系。文章详细解析了解题思路,包括递归算法的应用和记忆化搜索技巧,最终实现了问题的有效解决。

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

最近刷题碰到一题有趣的题目,其实难道不是很高,不过一开始想的复杂化了。题目还是比较有意思的。

整个公司的人员结构可以看作是一棵标准的多叉树。树的头节点是公司唯一的老板,除老板外,每个员工都有唯一的直接上级,叶节点是没有任何下属的基层员工,除基层员工外,每个员工都有一个或多个直接下级,另外每个员工都有一个快乐值。
这个公司现在要办 party,你可以决定哪些员工来,哪些员工不来。但是要遵循如下的原则:
1.如果某个员工来了,那么这个员工的所有直接下级都不能来。
2.派对的整体快乐值是所有到场员工快乐值的累加。
3.你的目标是让派对的整体快乐值尽量大。
给定一棵多叉树,请输出派对的最大快乐值。
输入描述:
第一行两个整数 n 和 root,n 表示公司的总人数,root 表示公司的老板。
第二行 n 个整数 happy_i 表示员工 i 的快乐值。
接下来 n - 1 行每行两个整数 u_i 和 v_i 表示 u_i 是 v_i 的直接上级。
输出描述:
输出一个整数表示最大快乐值。
示例1
输入
复制
3 1
5 1 1
1 2
1 3
输出
复制
5
备注:
1 \le n \le 5000001≤n≤500000
0 \le happy_i \le 10000≤happy
i

≤1000
输入保证是一棵树

这题一开始让我懵了一下,因为它不是一颗二叉树,他是多叉树。
其实在类当中放一个子节点的数组就可以了,
然后辅以递归来求解。
这里的本质就是选与不选,犹如打家劫舍,零钱兑换。
我觉得是可以用动态规划的,,但是这里参考评论区我用了记忆化递归。
我尝试过如果不存一下中间的最大值,那么会超时。
递归的过程是这样的,两种选择,选择这一个节点,和不选择这一个节点。
选择就直接加上它的开心值,不选择就将他孩子节点的值都加上。
然后return max(选择之和, 不选择之和),当然为了冗余运算,可以在树类里面使用一个max_happy, 来保存。
也就是说,当max_happy != 0, 就return max_happy

import java.util.*;

public class Main {
    public static class TreeNode {
        public int val; //快乐值
        public List<TreeNode> child;
        public TreeNode parent;
        public int max_happy;
        public TreeNode(int val) {
            this.val = val;
            this.parent = null;
            this.child = new ArrayList<TreeNode>();
            this.max_happy = 0;
        }
    }
    public static int dfs(TreeNode root) {
        int with_cur = root.val;
        int without_cur = 0;

        if(root.max_happy != 0)
            return root.max_happy;

        for(TreeNode num : root.child) {
            for(TreeNode ch : num.child) {
                with_cur += dfs(ch);
            }
        }

        for(TreeNode num : root.child) {
            without_cur += dfs(num);
        }

        root.max_happy = Math.max(with_cur, without_cur);
        return root.max_happy;

    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int root = in.nextInt();
        TreeNode[] company = new TreeNode[n];
        for(int i = 0; i < n; i ++) {
            int x = in.nextInt();
            company[i] = new TreeNode(x);
        }

        for(int i = 0; i < n - 1; i ++) {
            int u_i = in.nextInt();
            int v_i = in.nextInt();
            u_i -= 1;
            v_i -= 1;
            company[v_i].parent = company[u_i];
            company[u_i].child.add(company[v_i]);
        }
        int ans = 0;
        for(TreeNode num : company) {
            if(num.parent == null) {
                ans += dfs(num);
            }
        }
        System.out.println(ans);
    }
}

此代码通过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值