树形DP

树形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])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值