二叉树 — 最大happy值问题

员工信息类

public static class Employee {
        int happy; //每个员工都有happy值
        List<Employee> nexts; //这名员工有哪些直接下级

        public Employee(int h) {
            this.happy = h;
            nexts = new ArrayList<>();
        }
    }

公司的每个员工都符合Employee类的描述,整个公司的人员结构可以看做是一个标准的,没有环的多叉树(每个员工只有一个直接上级),树的头结点是公司唯一的老板,除老板之外的每个员工都有唯一的直接上级。叶结点是没有任何下属的基层员工(nexts列表为null),除基层员工外,每个员工都有1个上级和多个直接下级。

派对的最大欢乐值:
一个公司要举办Party,你可以决定哪些员工来,哪些员工不来,员工之间有上下级关系。规则:

  1. 如果某个员工来了,那么这个员工所有的直接下级都不能来
  2. 排队的整体欢乐值是所有到场员工快乐值的累加。
  3. 你的目标是让排队的整体快乐值尽量大值

给定一个多叉树的头结点,返回派对的最大欢乐值。

递归方式
以boss节点为例,最大值的情况有两种:1是boss来 2是boss不来, 如果boss不来的话,那么它的直属下级,可能来也可能不来,所以要求出boss来的最大值,和boss不来的最大值,并进行比较取较大的一个。 每个节点都可以看做是boss节点,如果当前节点不来,下级节点都可能来,可能不来。以此来构建Info类:

public static class Info {
        int yes;
        int no;

        public Info(int y, int n) {
            this.yes = y;
            this.no = n;
        }
    }
 public static int maxHappy1(Employee boss) {
        if (boss == null) {
            return 0;
        }
        Info allInfo = process1(boss);
		//boss节点来的最大happy值和boss节点不来的最大happy值,取较大的一个
        return Math.max(allInfo.no, allInfo.yes);
    }

    public static Info process1(Employee e) {
        if (e == null) {
            return new Info(0, 0);
        }
		//如果来,要加上当前节点的happy值
        int yes = e.happy;
        //如果不来,当前节点happy值为0
        int no = 0;
        for (Employee next : e.nexts) {
        	//递归调用process1
            Info nextInfo = process1(next);
            //如果当前节点来,那么要累加上下级节点不来时的happy值
            yes += nextInfo.no;
            //如果当前节点不来,那么下级节点可能来,也可能不来,取两个中的较大值
            no += Math.max(nextInfo.no, nextInfo.yes);
        }
        //构建当前节点Info信息,供上层调用
        return new Info(yes, no);
    }

暴力方式

 public static int maxHappy2(Employee boss) {
        if (boss == null) {
            return 0;
        }
        //boss为false 会先走else 也会进行累加
        return process2(boss, false);
    }
	//e:当前节点
	//up : true  代表当前节点来
	//up : false 代表当前节点不来
    public static int process2(Employee e, boolean up) {
        if (up) {
            int ans = 0;
            for (Employee next : e.nexts) {
                ans += process2(next, false);
            }
            return ans;
        } else {
        	//当前节点happy值
            int p1 = e.happy;
            int p2 = 0;
            for (Employee next : e.nexts) {
                p1 += process2(next, true);
                p2 += process2(next, false);
            }
            //取较大的一个
            return Math.max(p1, p2);
        }
    }

生成Employee
给定下属节点最大值,最大层级,最大happy值,递归调用生成Employee。

public static Employee generateBoss(int maxHappy, int maxLevel, int maxNexts) {
        if (Math.random() < 0.02) {
            return null;
        }
        Employee boss = new Employee((int) (Math.random() * maxHappy));
        generateNexts(boss, 1, maxLevel, maxNexts, maxHappy);
        return boss;
    }

    public static void generateNexts(Employee boss, int level, int maxLevel, int maxNexts, int maxHappy) {
        if (level > maxLevel) {
            return;
        }
        int nextSize = (int) (Math.random() * maxNexts);
        for (int i = 0; i < nextSize; i++) {
            Employee e = new Employee((int) (Math.random() * maxHappy));
            boss.nexts.add(e);
            generateNexts(e, level + 1, maxLevel, maxNexts, maxHappy);
        }
    }

测试

  public static void main(String[] args) {
        int maxHappy = 100;
        int nextSize = 10;
        int maxLevel = 10;
        int testNum = 1000;

        for (int i = 0; i < testNum; i++) {
            Employee boss = generateBoss(maxHappy, maxLevel, nextSize);
            if (maxHappy1(boss) != maxHappy2(boss)){
                System.out.println("Fuck!!");
                break;
            }
        }
        System.out.println("finish");
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值