树形DP
举例
二叉树节点间最大距离
一个二叉树中,任意两个结点的最大距离。
自己的解法
public static class TreeNode {
public int val ;
public TreeNode left = null;
public TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
/**
* 1. 最长距离不路过root,
* 2. 最长距离路过root
* @param root
* @return
*/
public static int maxDistance(TreeNode root){
if (root == null){
return 0 ;
}
//每个节点的最大距离分为上述的两种情况
//这里需要重复的计算节点的高度
return Math.max(height(root.left)+height(root.right)+1 ,
Math.max(maxDistance(root.left) , maxDistance(root.right))) ;
}
public static int height(TreeNode root){
if (root == null){
return 0 ;
}
if (root.left == null && root.right == null){
return 1 ;
}
return Math.max(height(root.left) , height(root.right))+1 ;
}
左神的解法
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
//方法入口
public static int maxDistance(Node head) {
int[] record = new int[1];
return posOrder(head, record);
}
public static class ReturnType{
public int maxDistance;
public int h;
public ReturnType(int m, int h) {
this.maxDistance = m;;
this.h = h;
}
}
public static ReturnType process(Node head) {
if(head == null) {
return new ReturnType(0,0);
}
ReturnType leftReturnType = process(head.left);
ReturnType rightReturnType = process(head.right);
int includeHeadDistance = leftReturnType.h + 1 + rightReturnType.h;
int p1 = leftReturnType.maxDistance;
int p2 = rightReturnType.maxDistance;
int resultDistance = Math.max(Math.max(p1, p2), includeHeadDistance);
int hitself = Math.max(leftReturnType.h, leftReturnType.h) + 1;
return new ReturnType(resultDistance, hitself);
}
public static int posOrder(Node head, int[] record) {
if (head == null) {
record[0] = 0;
return 0;
}
int lMax = posOrder(head.left, record);
int maxfromLeft = record[0];
int rMax = posOrder(head.right, record);
int maxFromRight = record[0];
int curNodeMax = maxfromLeft + maxFromRight + 1;
record[0] = Math.max(maxfromLeft, maxFromRight) + 1;
return Math.max(Math.max(lMax, rMax), curNodeMax);
}
拓展题型
1. 最大快乐值
题目
某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上司,现在已知每个人的活跃指数和上司关系(当然不可能存在环),求邀请哪些人(多少人)来能使得晚会的总活跃指数最大。
分析
此问题的所有情况:
- 当前员工来的时候,他的分支上最大的快乐值。
- 当前员工不来的时候,他的分支上最大的快乐值。
- 当前员工来 - > 直接下属不能来 -> 最大值就是所有下属不能来的情况下最大的快乐值(也就是转移到了情况2)。
- 当前员工不来 - > 直接下属可以来,可以不来 - > 最大值就是每个下属来或者不来取max,然后sum。
代码
//员工类
public static class Employee {
public int happy ;
public List<Employee> employees ;
}
//每个员工对应的信息
public static class Info {
//此员工来的时候,以他为根节点,最大的快乐值
public int comeHappy ;
//此员工不来的时候,以他为根节点,最大的快乐值
public int notComeHappy ;
public Info(int comeHappy , int notComeHappy){
this.comeHappy = comeHappy ;
this.notComeHappy = notComeHappy ;
}
}
//方法入口
public static int maxHappy(Employee root){
if (root == null){
return 0 ;
}
Info info = process(root) ;
return Math.max(info.comeHappy , info.notComeHappy) ;
}
public static Info process(Employee employee){
if (employee.employees.isEmpty()){
//最底层员工,如果来就是自己的happy,如果不来就是0
return new Info(employee.happy , 0 ) ;
}else{
//非底层员工,employee 可以选择参加或者不参加
//如果参加就是emloyee的欢乐值加上下级不参加的快乐值
int come = employee.happy ;
//如果不参加就是 每个手下参加或者不参加的最大值的sum
int notCome = 0 ;
List<Employee> employees = employee.employees ;
Info info ;
for (Employee e : employees) {
info = process(e) ;
//第一种情况
come += info.notComeHappy ;
//第二种情况
notCome += Math.max(info.comeHappy , info.notComeHappy) ;
}
return new Info(come , notCome) ;
}
}
2. 放置哨兵
题目
有n个点,在某些点上放置哨兵,每个哨兵可以监控和它有边相连的点,问监视所有的点需要的最少的哨兵数。也就是说一颗n个结点的树,要求选出其中的一些顶点,使得对于树中的每条边(u, v),u和v至少有一个被选中,要求给出选中顶点数最少的方案
分析
分析一下:
- 第一种父节点无人站岗时,子节点必须站岗。
- 第二种父节点站岗时,子节点站岗和不站岗的最小值。
代码
dp[node][0] += dp[children][1]
dp[node][1] += min(dp[children][0] , dp[children][1])