求公司派对的最大快乐值

求公司派对的最大快乐值

提示:本节仍然是重点说二叉树的DP递归套路,非常重要而且容易理解

二叉树的动态规划树形DP递归套路系列文章有这些,可以帮助你快速掌握树形DP的题目解题思想,就一个套路:
(1)判断二叉树是否为平衡二叉树?树形DP,树形动态规划的递归套路
(2)求二叉树中,任意两个节点之间的距离最大值是多少
(3)求二叉树中,包含的最大二叉搜索子树的节点数量是多少


题目

公司的员工类是:

public static class Employee{
        public int happy;
        public ArrayList<Employee> nexts;//直接下属
        public Employee(int h){
            happy = h;
            nexts = new ArrayList<>();//空动态数组?就是列表,没问题
        }
    }

内部有happy值,可能一个员工还有一堆下属:nexts中,那就是多叉树
树的头节点就是董事长
树的叶节点就是没有员工的节点。
每个员工只有一个上级,不会重复的

现在公司要办party,请你发请柬邀请员工,你可以决定哪个员工来还是不来,但是:
(1)一个员工它来了,它的直接下属不能来;
(2)派对的快乐值是所有到场员工快乐值的总和;
(3)你的目标是使得整体派对值最大化;
(4)给你董事长头节点,请你返回最大派对值;


一、审题

示例:
如果A员工来,那A的下属决不能来
如果A不来,那他的下属可以来,也可以不来


二、树形动态规划的递归套路:树形DP

95%的二叉树动态规划问题,都可以用以下套路解决:
一、定义个信息类:Info
收集x左树和右树都有的信息(左右树都有哦,而不是针对某单独的左树或者右树),比如是否平衡?树的高度,总之就是有的信息,不管你是String还是Boolean还是Integer类型的信息。经常是要讨论与x有关,还是 与x无关。

二、树形DP递归套路: 来到x节点
1)base case:考虑叶节点应该返回的信息Info
2)先收集左树和右树的信息Info
3)综合2)整理x自己的信息,并返回;

三、从题目给的二叉树head开始求(2),得到了一个head的信息Info,找里面咱们要用的那个信息:比如是否平衡?返回它。

来,咱们举例说明:实践知真理!


三、解题思路:

本题仍然是树形DP,虽然不是二叉树,但是多叉树动态规划也叫树形DP

一、定义个信息类:Info
收集x左树和右树都有的信息(左右树都有哦,而不是针对某单独的左树或者右树),比如是否平衡?树的高度,总之就是有的信息,不管你是String还是Boolean还是Integer类型的信息。经常是要讨论与x有关,还是 与x无关。
咱们讨论一个员工x来还是不来?
来就与x有关,不来就是和员工x无关
如果员工来【至少x自己的happy值要算上,当然它的多个直接下属不能来】,x极其下面整个树的派对最大值是多少?yes
不过员工不来【x自己提供0快乐值,但是它的下属可以来,可以不来】,x极其下面整个树的派对最大值是多少?no
yes和no就是咱们要收集的信息
统计x极其下面的多叉树,整体最大的快乐值应该是多少?

public static class Info{
        public int yes;//来或者不来的派对值
        public int no;
        public Info(int y, int n){
            yes = y;
            no = n;
        }
    }

二、树形DP递归套路: 来到x节点
那就设定一个函数来统计把,process(Node x)
1)base case:考虑叶节点应该返回的信息Info
没有员工的节点x,就是x.nexts=null,那可以统计自己来,还是不来的最大快乐值
自己来就是x.happy,不来,就会0快乐。
返回即可

//终止条件:
        if (head.nexts == null) return new Info(head.happy, 0);//自己来不来

2)先收集左树和右树的信息Info
这好说:
对于多叉树,就是收集下属所有员工的信息:

for(Employee next:head.nexts){
            Info nextInfo = process(next);//先看看员工来不来

3)综合2)整理x自己的信息,并返回;
整合信息,在每一个2)循环中,咱,需要讨论,
——如果x来,x提供x.happy,那所有next员工不能来,这样的派对最大值是多少?yes
在这里插入图片描述

——如果x不能来,x提供了0快乐值,但是你可以决定next来,还是不来,他们能提供的最大值是多少?no
在这里插入图片描述

这样就可以算出yes和no信息
因此需要把for循环中的结果累加到yes和no上。

for(Employee next:head.nexts){
            Info nextInfo = process(next);//先看看员工来不来
            //对其所有下属
            yes += nextInfo.no;//自己来了,员工决不能来
            no += Math.max(nextInfo.yes, nextInfo.no);//自己不来的话,得看员工来不来的最大值
        }

手撕代码整体实现:

//复习
    public static Info f(Employee x){
        if (x.nexts == null) return new Info(x.happy, 0);

        //所有x的员工们的情况:
        int yes = x.happy;//我x来
        int no = 0;//我x不来,x之下最大快乐值

        for(Employee e: x.nexts){
            Info eHappy = f(e);
            //我来,下属不能来
            yes += eHappy.no;
            no += Math.max(eHappy.yes, eHappy.no);//我不来,员工随意,他们的最大值加我
        }

        return new Info(yes, no);//返回x的信息
    }

三、从题目给的二叉树head开始求(2),得到了一个head的信息Info,找里面咱们要用的那个信息:比如是否平衡?返回它。
调用,自然是求董事长的Info
然后对比Info的yes和no,谁更大呢?就看董事长来还是不来?

//调用
    public static int partyMaxHappy(Employee head){
        if (head == null) return 0;

        Info info = f(head);
        return Math.max(info.yes, info.no);
    }

测试一下:


    //公司架构怎么样:
    //             boss:100
    //       m1:1000      m2:1000     m3:1000
    // w1:0  w2:78   w3:58 w4:44  w5:100 w6:22
    public static Employee generateEmployee(){
        Employee boss = new Employee(100);
        Employee m1 = new Employee(1000);
        Employee m2 = new Employee(1000);
        Employee m3 = new Employee(1000);
        Employee w1 = new Employee(0);
        Employee w2 = new Employee(78);
        Employee w3 = new Employee(58);
        Employee w4 = new Employee(44);
        Employee w5 = new Employee(100);
        Employee w6 = new Employee(22);
        boss.nexts.add(m1);
        boss.nexts.add(m2);
        boss.nexts.add(m3);
        m1.nexts.add(w1);
        m1.nexts.add(w2);
        m2.nexts.add(w3);
        m2.nexts.add(w4);
        m3.nexts.add(w5);
        m3.nexts.add(w6);

        return boss;
    }

    public static void test(){
        Employee boss = generateEmployee();
        int max = getMaxHappy(boss);
        System.out.println(max);

        int max2 = partyMaxHappy(boss);
        System.out.println(max2);
    }

    public static void main(String[] arges){
        //简称psvm,骚得很
        test();
    }

结果如下

3000
3000

总结

提示:重要经验:

1)不管是二叉树,还是多叉树,树形DP都是同一个套路,就是去各个子树上收集信息,然后整理x节点自己的信息,往上传;
2)树形DP的递归套路要熟悉,不断使用,突破,然后融会贯通;
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰露可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值