一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
派对的最大快乐值
员工信息的定义如下:
public static class Employee{
public int happy;//这名员工可以带来的快乐值
List<Employee> subordinates;//这名员工有哪些直接下级
}
公司的每个员工都符合Employee类的描述。整个公司的人员结构可以看作是一棵标准的、没有环的多叉树。树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外,每个员工都有一个或多个直接下级。
这个公司现在要办party,你可以决定哪些员工来,哪些员工不来,规则:
- 如果某个员工来了,那么这个员工的所有直接下级都不能来
- 派对的整体快乐值是所有到场员工快乐值的累加
- 你的目标是让派对的整体快乐值尽量大
给定一棵多叉树的头节点boss,请返回派对的最大快乐值。
第一种可能性:X结点来(就是给X结点发请柬),假设X有三个直接下级a,b,c,如果给X发请柬的话,快乐值就是:
X自己的快乐值 + a不来情况下整颗子树的快乐值 + b不来情况下整颗子树的快乐值 + c不来情况下整颗子树的快乐值,
因为a,b,c不能来。
第二种可能性:X结点不来(就是不给X发请柬),假设X有三个直接下级a,b,c,如果不给X发请柬的话,快乐值就是:
X自己的快乐值0 + max{a来的情况下整颗树的快乐值,a不来的情况下整棵树的快乐值} + max{b来的情况下整颗树的快乐值,b不来的情况下整棵树的快乐值} + max{c来的情况下整颗树的快乐值,c不来的情况下整棵树的快乐值}
所以任何子树都需要返回的信息就是:
- 头结点来的情况下,整颗子树的快乐值是多少
- 头结点不来的情况下,整颗子树的快乐值是多少
public static class Info{
public int yes;// 对于任何子树都要返回 头结点来的情况下,整颗子树的快乐值
public int no;// 对于任何子树都要返回 头结点不来的情况下,整颗子树的快乐值
public Info(int y,int n) {
yes=y;
no=n;
}
}
完整代码:
package com.harrison.class08;
import java.util.ArrayList;
import java.util.List;
public class Code04_MaxHappy {
public static class Employee{
public int happy;//这名员工可以带来的快乐值
List<Employee> nexts;//这名员工有哪些直接下级
public Employee(int h) {
happy = h;
nexts = new ArrayList<>();
}
}
public static class Info{
public int yes;// 对于任何子树都要返回 头结点来的情况下,整颗子树的快乐值
public int no;// 对于任何子树都要返回 头结点不来的情况下,整颗子树的快乐值
public Info(int y,int n) {
yes=y;
no=n;
}
}
public static Info process1(Employee x) {
if(x==null) {
return new Info(0, 0);
}
// X来的情况下先直接获得X的快乐值
int yes=x.happy;
// X不来情况下,快乐值就是0
int no=0;
// X来:累加上X的直接下级不来的情况下的快乐值
// X不来:累加上X的直接下级来的情况和不来的情况 的 最大值
for(Employee next:x.nexts) {
Info nextInfo=process1(next);
yes+=nextInfo.no;
no+=Math.max(nextInfo.yes, nextInfo.no);
}
return new Info(yes, no);
}
public static int maxHappy1(Employee head) {
Info allInfo=process1(head);
return Math.max(allInfo.yes, allInfo.no);
}
// 当前来到的节点叫cur,
// up表示cur的上级是否来,
// 该函数含义:
// 如果up为true,表示在cur上级已经确定来,的情况下,cur整棵树能够提供最大的快乐值是多少?
// 如果up为false,表示在cur上级已经确定不来,的情况下,cur整棵树能够提供最大的快乐值是多少?
public static int process2(Employee cur, boolean up) {
if (up) { // 如果cur的上级来的话,cur没得选,只能不来
int ans = 0;
for (Employee next : cur.nexts) {
ans += process2(next, false);
}
return ans;
} else { // 如果cur的上级不来的话,cur可以选,可以来也可以不来
int p1 = cur.happy;
int p2 = 0;
for (Employee next : cur.nexts) {
p1 += process2(next, true);
p2 += process2(next, false);
}
return Math.max(p1, p2);
}
}
public static int maxHappy2(Employee boss) {
if (boss == null) {
return 0;
}
return process2(boss, false);
}
public static void generateNexts(Employee e,int level,int maxLevel,int maxNexts,int maxHappy) {
if(level>maxLevel) {
return ;
}
int nextSize=(int)(Math.random()*(maxNexts+1));
for(int i=0; i<nextSize; i++) {
Employee next=new Employee((int)(Math.random()*(maxHappy+1)));
e.nexts.add(next);
generateNexts(next, level+1, maxLevel, maxNexts, maxHappy);
}
}
public static Employee generateBoss(int maxLevel,int maxNexts,int maxHappy) {
if(Math.random()<0.02) {
return null;
}
Employee boss=new Employee((int)(Math.random()*(maxHappy+1)));
generateNexts(boss, 1, maxLevel, maxNexts, maxHappy);
return boss;
}
public static void main(String[] args) {
int maxLevel = 4;
int maxNexts = 7;
int maxHappy = 100;
int testTimes = 100000;
for (int i = 0; i < testTimes; i++) {
Employee boss = generateBoss(maxLevel, maxNexts, maxHappy);
if (maxHappy1(boss) != maxHappy2(boss)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
}