树形DP的详解

目录

树形DP套路

     使用前提

     套路详解

树形DP应用

     二叉树节点间的最大距离问题

     派对的最大快乐值 

树形DP套路

     使用前提

       如果题目求解目标是S规则,则求解流程可以定成以每一个节点为头节点的子树在S规则下的每一个答案,并且最终答案一定在其中。

     套路详解

       树形dp套路第一步: 以某个节点X为头节点的子树中,分析答案有哪些可能性,并且这种分析是以X的左子树、X的右子树和X整棵树的角度来考虑可能性的。

       树形dp套路第二步: 根据第一步的可能性分析,列出所有需要的信息。

       树形dp套路第三步: 合并第二步的信息,对左树和右树提出同样的要求,并写出信息结构。

       树形dp套路第四步: 设计递归函数,递归函数是处理以X为头节点的情况下的答案。包括设计递归的basecase,默认直接得到左树和右树的所有信息,以及把可能性做整合,并且要返回第三步的信息结构这四个小步骤。

        树形DP套路正是我们前面介绍的二叉树的递归套路的结构,也就是对于一个二叉树的题目,我可以向左树要信息,也可以向右树要信息,然后求解题目。在这里进行一次更深入的介绍。

树形DP应用

     二叉树节点间的最大距离问题

       从二叉树的节点a出发,可以向上或者向下走,但沿途的节点只能经过一次,到达节点b时路 径上的节点个数叫作a到b的距离,那么二叉树任何两个节点之间都有距离,求整棵树上的最大距离。 

       这个题目完全是按照树形DP的套路,进行分情况分析,树形DP的题目,大多数情况下,都是按照是不是包含头节点进行分类。如果不包含头节点,那么整棵树的最大距离,只能是左树的最大值和右树的最大值中最大的一个。如果包含头节点,那么整棵树最大的距离就是左树的高度加右树的高度加1。那么对这三种情况进行整体分析,我们需要从每棵树得到的信息就是每棵子树的最大具体还有高度。从而按照树形DP的编程套路进行书写即可。

   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) {//主函数调用
		return process(head).maxDistance;
	}
	
	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) {//递归过程,以head为头节点整体框架的搭建
		if(head == null) {//如果头节点为空,两个值都返回0
			return new ReturnType(0,0);
		}
		ReturnType leftReturnType = process(head.left);//从左树拿信息
		ReturnType rightReturnType = process(head.right);//从右树拿信息
		int includeHeadDistance = leftReturnType.h + 1 + rightReturnType.h;//包括头节点的最大距离的定义,为左树高度与右树高度的和加1
        //不包括头节点的两个情况
		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;//总树的高度,左树高度和右树高度的最大值加1
		return new ReturnType(resultDistance, hitself);//返回总树的最大距离和高度
	}

     派对的最大快乐值 

       员工信息的定义如下:

class Employee{
    public int happy;//这名员工可以带来的快乐值
    List<Employee>subordinates;//这名员工有哪些直接下级
}

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

       这个公司现在要办party,你可以决定哪些员工来,哪些员工不来。但是要遵循如下规则:  

       1.如果某个员工来了,那么这个员工的所有直接下级都不能来。

       2.派对的整体快乐值是所有到场员工快乐值的累加。

       3.你的目标是让派对的整体快乐值尽量大。

       给定一棵多叉树的头节点boss,请返回派对的最大快乐值。

       这个问题的解决采用的也是同样的思想,分为包括头节点和不包括头节点两种情况,如果包括头节点,那么它的直接下级不能参加,返回每一棵子树的最大的快乐值加和起来,加上自身的快乐值就是总体的最大快乐值。如果不包括头节点,那么它的直接下级可以参加也可以不参加,返回两者的最大值。从而按照树形DP的套路进行代码的书写。

public static class Employee{
     public int happy;
     public List<Employee> nexts;
}
public static int maxHappy<Employee boss){
     Info headInfo = process(boss);
     return Math.max(headInfo.laiMaxHappy,headInfo.buMaxHappy);
}
punlic static class Info{
     public int laiMaxHappy;
     public int buMaxHappy;
     public Info(int lai,int bu){
         laiMaxHappy = lai;
         buMaxHappy = bu;
     }
}
public static Info process(Employee x){
     if(x.nexts.isEmpty()){//x是基层员工的时候
         return new Info(x.happy,0);
     }
     int lai = x.happy;//x来的情况下,整棵树的最大收益
     int bu = 0;//x不来的情况下,整棵树的最大收益
     for(Employee next : x.nexts){
         Info nextInfo = process(next);
         lai += nextInfo.buMaxHappy;//x来的话,它的直接下级都不能来,后面的来
         bu += Math.max(nextInfo.laiMaxHappy,nextInfo.buMaxHappy);//x不来的话,它的直接下级可以选择来不来
     }
     return new Info(lai,bu);//最终返回来和不来情况的最大值
}
         
     
         
  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

互联网的猫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值