【Leetcode】968. Binary Tree Cameras 968. 监控二叉树

1
2

解法

树的最小支配集问题,参考:这里

解法一:贪心法

先做DFS【就是先根遍历】,取得遍历节点编号及其父节点编号
然后倒过来,逐一判断:

最小支配集
【何时加入】若当前节点没被覆盖,且它的父节点不在支配集里
【加入谁】当前节点的父节点
【标记什么】当前节点,当前节点的父节点,当前节点父父节点都标记为已覆盖
最小点覆盖
【何时加入】若当前节点及其父节点均未覆盖
【加入谁】当前节点的父节点
【标记什么】当前节点,当前节点的父节点标记为已覆盖
最大独立集
【何时加入】若当前节点未覆盖
【加入谁】当前节点
【标记什么】当前节点,当前节点的父节点标记为已覆盖
注意: 根节点的父节点为自己,只有【最小点覆盖】不检查根节点,其它都检查

class Solution(object):
    def minCameraCover(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        from collections import defaultdict
        p = []
        def dfs(prev,root):
            if root:
                i = len(p)
                p.append(prev)
                dfs(i,root.left)
                dfs(i,root.right)
        dfs(0,root)
        n = len(p)
        if n==1:
            return 1
        mark = set()
        used = set()
        ans = 0
        for i in xrange(n-1,-1,-1):
            if i not in mark:
                if p[i] not in used:
                    used.add(p[i])
                    ans += 1
                mark.add(i)
                mark.add(p[i])
                mark.add(p[p[i]])
        return ans

解法二:树形动态规划

最小点覆盖和最大独立集都比较简单,只有2个状态,分别是标记和不标记

对于最小支配集,每个子树3个状态:

  1. 状态0:根被标记,整个子树都被覆盖的最小标记数目
  2. 状态1:根未被标记,整个子树被覆盖,且至少有一个子节点被标记
  3. 状态2:根未被标记,整个子树被覆盖,且没有子节点被标记

每个状态如何递归:

  1. 状态0:每个子树的3个状态的最小值之和+1:
    dp[root][0] = min(dp[root.left])+min(dp[root.right])+1

  2. 状态1:【如果根没有孩子,dp[root][1]为INF】根未被标记时子树不可以是状态3。所以是前两个状态取最小值之和。但是如果每个子节点的最小值都是状态1,那么就和根是状态1的假设矛盾了。所以要挑一个节点取状态0,这必然会使结果增加,那么选增加得最少的那个,即dp[u][0]-dp[u][1]最小的那个指定为状态0。

    不可能是状态3是因为如果根没有标记,儿子没有标记,根还被覆盖了,可能是根的父亲标记了,但是如果孙子也没有标记,那么儿子就不可能被标记,矛盾。

  3. 状态2:此时子树只可能是状态1。
    dp[root][2] = dp[root.left][1]+dp[root.right][1]

最后取根节点的状态1和状态0里最小的那个

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def minCameraCover(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        INF = 0x7fffffff
        def solve(root):
            if root.left and root.right:
                left = solve(root.left)
                right = solve(root.right)
                return min(left)+min(right)+1, min(left[0]+min(right[:-1]), min(left[:-1])+right[0]),left[1]+right[1]
            res = None
            if root.left:
                res = solve(root.left)
            elif root.right:
                res = solve(root.right)
            if res!=None:
                return min(res)+1, res[0], res[1]
            return 1, INF, 0
        return min(solve(root)[:-1])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值