📌  相关文章
📜  从叶子节点开始烧掉一棵树的最短时间

📅  最后修改于: 2022-05-13 01:57:17.312000             🧑  作者: Mango

从叶子节点开始烧掉一棵树的最短时间

给定一棵二叉树和这棵树的叶节点。众所周知,在 1 秒内,连接到给定节点(左孩子、右孩子和父母)的所有节点都会在 1 秒内被烧毁。然后通过一个中间连接的所有节点在 2 秒内被烧毁,以此类推。任务是找到燃烧完整二叉树所需的最短时间。
例子:

Input : 
            1
       /       \
      2          3
    /  \          \
   4    5          6
      /   \         \
     7     8         9
                      \
                       10
Leaf = 8
Output : 7
Initially 8 is set to fire at 0th sec.
            1
       /       \
      2          3
    /  \          \
   4    5          6
      /   \         \
     7     F         9
                      \
                       10
After 1s: 5 is set to fire.
            1
       /       \
      2          3
    /  \          \
   4    F          6
      /   \         \
     7     F         9
                      \
                       10
After 2s: 2, 7 are set to fire.
            1
       /       \
      F          3
    /  \          \
   4    F          6
      /   \         \
     F     F         9
                      \
                       10
After 3s: 4, 1 are set to fire.
            F
       /       \
      F          3
    /  \          \
   F    F          6
      /   \         \
     F     F         9
                      \
                       10
After 4s: 3 is set to fire.
            F
       /       \
      F          F
    /  \          \
   F    F          6
      /   \         \
     F     F         9
                      \
                       10
After 5s: 6 is set to fire.
            F
       /       \
      F          F
    /  \          \
   F    F          F
      /   \         \
     F     F         9
                      \
                       10
After 6s: 9 is set to fire.
            F
       /       \
      F          F
    /  \          \
   F    F          F
      /   \         \
     F     F         F
                      \
                       10
After 7s: 10 is set to fire.
            F
       /       \
      F          F
    /  \          \
   F    F          F
      /   \         \
     F     F         F
                      \
                       F
It takes 7s to burn the complete tree.

这个想法是为每个节点存储附加信息:

  • 左子树的深度。
  • 右子树的深度。
  • 火灾从第一个燃烧的叶节点开始到达当前节点所需的时间。
  • 一个布尔变量,用于检查初始烧毁节点是否在以当前节点为根的树中。

在继续使用该方法之前,让我们看一下下面的树:

1
          /      \          
       2            3
     /   \         /
    4     5       6 
   /     / \
  8     9   10
       /
      11

在上面的树中,如果我们将叶节点 11 设置为着火。

  1. 1s内,火势将到达节点9。
  2. 2s后,火将到达节点5。
  3. 在第 3 秒,火将到达节点 2 和 10。这里有一个观察结果:
    • 在 2s 内火灾到达节点 5。对于节点 5,最初燃烧的叶子在它的左子树中,因此燃烧右子树所需的时间将是右子树的高度为 1。因此,火灾到达节点 10 在 ( 2+1) = 3 秒。
    • 同样,对于节点 2。火在 3 秒内从右子树到达节点 2。因此,燃烧左子树所花费的时间将是它的高度。

所以解决方案是应用递归并为每个节点计算以下所需的值:

  • 左深度。
  • 正确的深度。
  • 火灾到达当前节点所需的时间。
  • 当前子树是否包含初始烧毁的叶子节点。

因此,燃烧任何子树所需的最短时间为:

因此,要找到烧毁整棵树所需的时间,我们需要计算每个节点的上述值,并取该值的最大值。

下面是上述方法的实现:

C++
// C++ program to find minimum time required
// to burn the binary tree completely
 
#include 
using namespace std;
 
// Tree Node
struct Node {
    int data;
    Node* left;
    Node* right;
 
    Node()
    {
        left = NULL;
        right = NULL;
    }
};
 
// Utility function to create a new Node
Node* newNode(int val)
{
    Node* temp = new Node;
 
    temp->data = val;
 
    return temp;
}
 
/*
        ***********ADDITIONAL INFO*************
        lDepth - maximum height of left subtree
        rDepth - maximum height of right subtree
        contains - stores true if tree rooted at current
           node contains the first burnt node time - time to reach
           fire from the initially burnt leaf node to this node
*/
struct Info {
    int lDepth;
    int rDepth;
    bool contains;
 
    int time;
 
    Info()
    {
        lDepth = rDepth = 0;
        contains = false;
 
        time = -1;
    }
};
 
/*
        Function to calculate time required to burn
        tree completely
 
        node - address of current node
        info - extra information about current node
        target - node that is fired
        res - stores the result
*/
Info calcTime(Node* node, Info& info, int target, int& res)
{
 
    // Base case: if root is null
    if (node == NULL) {
        return info;
    }
 
    // If current node is leaf
    if (node->left == NULL && node->right == NULL) {
 
        // If current node is the first burnt node
        if (node->data == target) {
            info.contains = true;
            info.time = 0;
        }
        return info;
    }
 
    // Information about left child of root
    Info leftInfo;
    calcTime(node->left, leftInfo, target, res);
 
    // Information about right child of root
    Info rightInfo;
    calcTime(node->right, rightInfo, target, res);
 
    // If left subtree contains the fired node then
    // time required to reach fire to current node
    // will be (1 + time required for left child)
    info.time = (node->left && leftInfo.contains)
                    ? (leftInfo.time + 1)
                    : -1;
 
    // If right subtree contains the fired node then
    // time required to reach fire to current node
    // will be (1 + time required for right child)
    if (info.time == -1)
        info.time = (node->right && rightInfo.contains)
                        ? (rightInfo.time + 1)
                        : -1;
 
    // Storing(true or false) if the tree rooted at
    // current node contains the fired node
    info.contains
        = ((node->left && leftInfo.contains)
           || (node->right && rightInfo.contains));
 
    // Calculate the maximum depth of left subtree
    info.lDepth
        = !(node->left)
              ? 0
              : (1 + max(leftInfo.lDepth, leftInfo.rDepth));
 
    // Calculate the maximum depth of right subtree
    info.rDepth
        = !(node->right)
              ? 0
              : (1
                 + max(rightInfo.lDepth, rightInfo.rDepth));
 
    // Calculating answer
    if (info.contains) {
        // If left subtree exists and
        // it contains the fired node
        if (node->left && leftInfo.contains) {
            // calculate result
            res = max(res, info.time + info.rDepth);
        }
 
        // If right subtree exists and it
        // contains the fired node
        if (node->right && rightInfo.contains) {
            // calculate result
            res = max(res, info.time + info.lDepth);
        }
    }
}
 
// Driver function to calculate minimum
// time required
int minTime(Node* root, int target)
{
    int res = 0;
    Info info;
 
    calcTime(root, info, target, res);
 
    return res;
}
 
// Driver Code
int main()
{
    Node* root = newNode(1);
    root->left = newNode(2);
    root->right = newNode(3);
    root->left->left = newNode(4);
    root->left->right = newNode(5);
    root->right->left = newNode(6);
    root->left->left->left = newNode(8);
    root->left->right->left = newNode(9);
    root->left->right->right = newNode(10);
    root->left->right->left->left = newNode(11);
 
    // target node is 8
    int target = 11;
 
    cout << minTime(root, target);
 
    return 0;
}


Java
// Java program to find minimum time required
// to burn the binary tree completely
 
public class GFG {
 
    // Tree Node
    static class Node {
        int data;
        Node left, right;
 
        Node(int data)
        {
            this.data = data;
            this.left = null;
            this.right = null;
        }
    }
 
    /*
        ***********ADDITIONAL INFO*************
        lDepth - maximum height of left subtree
        rDepth - maximum height of right subtree
        contains - stores true if tree rooted at current node
                contains the first burnt node
        time - time to reach fire from the initially burnt leaf
            node to this node
    */
    static class Data {
        int leftDepth, rightDepth, time;
        boolean contains;
 
        Data()
        {
            contains = false;
            leftDepth = rightDepth = 0;
            time = -1;
        }
    }
 
    /*
        Function to calculate time required to burn
        tree completely
         
        node - address of current node
        info - extra information about current node
        target - node that is fired
        res - stores the result
    */
    public static void getResult(Node node, Data data, int target)
    {
 
        // Base case: if root is null
        if (node == null) {
            return;
        }
 
        // If current node is leaf
        if (node.left == null && node.right == null) {
 
            // If current node is the first burnt node
            if (node.data == target) {
                data.contains = true;
                data.time = 0;
            }
            return;
        }
 
        // Information about left child
        Data leftData = new Data();
        getResult(node.left, leftData, target);
 
        // Information about right child
        Data rightData = new Data();
        getResult(node.right, rightData, target);
 
        // If left subtree contains the fired node then
        // time required to reach fire to current node
        // will be (1 + time required for left child)
        data.time = (leftData.contains) ? (leftData.time + 1) : -1;
 
        // If right subtree contains the fired node then
        // time required to reach fire to current node
        // will be (1 + time required for right child)
        if (data.time == -1)
            data.time = (rightData.contains) ? (rightData.time + 1) : -1;
 
        // Storing(true or false) if the tree rooted at
        // current node contains the fired node
        data.contains = (leftData.contains || rightData.contains);
 
        // Calculate the maximum depth of left subtree
        data.leftDepth = (node.left == null) ? 0 : (1 + Math.max(leftData.leftDepth, leftData.rightDepth));
 
        // Calculate the maximum depth of right subtree
        data.rightDepth = (node.right == null) ? 0 : (1 + Math.max(rightData.leftDepth, rightData.rightDepth));
 
        // Calculating answer
        if (data.contains) {
 
            // If left subtree exists and
            // it contains the fired node
            if (leftData.contains) {
 
                // calculate result
                res = Math.max(res, data.time + data.rightDepth);
            }
 
            // If right subtree exists and it
            // contains the fired node
            if (rightData.contains) {
 
                // calculate result
                res = Math.max(res, data.time + data.leftDepth);
            }
        }
    }
 
    // To store the result
    public static int res;
 
    // Driver Code
    public static void main(String args[])
    {
 
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.left.left = new Node(4);
        root.left.right = new Node(5);
        root.right.left = new Node(6);
        root.left.left.left = new Node(8);
        root.left.right.left = new Node(9);
        root.left.right.right = new Node(10);
        root.left.right.left.left = new Node(11);
 
        int target = 11;
 
        res = 0;
        getResult(root, new Data(), target);
        System.out.println(res);
    }
}


Python3
# Python program to find minimum time required
# to burn the binary tree completely
 
# Definition for a  binary tree node
 
 
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
 
 
'''
    ***********ADDITIONAL INFO*************
    lDepth - maximum height of left subtree
    rDepth - maximum height of right subtree
    contains - stores true if tree rooted at current node
               contains the first burnt node
    time - time to reach fire from the initially burnt leaf
           node to this node
'''
 
 
class Info:
    def __init__(self):
        self.lDepth = 0
        self.rDepth = 0
        self.contains = False
        self.time = -1
 
 
class Solution:
    # Class Variable
    res = 0
 
    '''
        Function to calculate time required to burn
        tree completely
 
        node - address of current node
        info - extra information about current node
        target - node that is fired
        res - stores the result
    '''
 
    def calcTime(self, node, info, target):
        # Base case: if root is null
        if node == None:
            return info
 
        if node.left == None and node.right == None:
            # If current node is the first burnt node
            if node.val == target:
                info.contains = True
                info.time = 0
            return info
 
        # Information about left child of root
        leftInfo = Info()
        leftInfo = self.calcTime(node.left, leftInfo, target)
 
        # Information about right child of root
        rightInfo = Info()
        rightInfo = self.calcTime(node.right, rightInfo, target)
 
        # If left subtree contains the fired node then
        # time required to reach fire to current node
        # will be (1 + time required for left child)
        info.time = leftInfo.time + \
            1 if (node.left and leftInfo.contains) else -1
 
        # If right subtree contains the fired node then
        # time required to reach fire to current node
        # will be (1 + time required for right child)
        if info.time == -1:
            info.time = rightInfo.time + \
                1 if (node.right and rightInfo.contains) else -1
 
        # Storing(true or false) if the tree rooted at
        # current node contains the fired node
        info.contains = (node.left and leftInfo.contains) or (
            node.right and rightInfo.contains)
 
        # Calculate the maximum depth of left subtree
        info.lDepth = 0 if (not node.left) else (
            1+max(leftInfo.lDepth, leftInfo.rDepth))
 
        # Calculate the maximum depth of right subtree
        info.rDepth = 0 if (not node.right) else (
            1+max(rightInfo.lDepth, rightInfo.rDepth))
 
        # Calculating answer
        if info.contains:
            # If left subtree exists and
            # it contains the fired node
            if node.left and leftInfo.contains:
                # calculate result
                self.res = max(self.res, info.time+info.rDepth)
 
            # If right subtree exists and it
            # contains the fired node
            if node.right and rightInfo.contains:
                # calculate result
                self.res = max(self.res, info.time+info.lDepth)
 
        return info
 
    # Driver function to calculate minimum
    # time required
    def solve(self, root, target):
        info = Info()
        self.calcTime(root, info, target)
        return self.res
 
 
# Driver Code
if __name__ == '__main__':
    # Construct tree shown in the above example
    root = TreeNode(1)
    root.left = TreeNode(2)
    root.right = TreeNode(3)
    root.left.left = TreeNode(4)
    root.left.right = TreeNode(5)
    root.right.left = TreeNode(6)
    root.left.left.left = TreeNode(8)
    root.left.right.left = TreeNode(9)
    root.left.right.right = TreeNode(10)
    root.left.right.left.left = TreeNode(11)
 
    # Target Leaf Node
    target = 11
 
    # Print min time to burn the complete tree
    s = Solution()
    print(s.solve(root, target))
 
# This code is contributed by Naman Taneja


C#
// C# program to find minimum time required
// to burn the binary tree completely
using System;
 
class GFG
{
 
    // Tree Node
    class Node
    {
        public int data;
        public Node left, right;
 
        public Node(int data)
        {
            this.data = data;
            this.left = null;
            this.right = null;
        }
    }
 
    /*
        ***********ADDITIONAL INFO*************
        lDepth - maximum height of left subtree
        rDepth - maximum height of right subtree
        contains - stores true if tree rooted at current node
                contains the first burnt node
        time - time to reach fire from the initially burnt leaf
            node to this node
    */
    class Data
    {
        public int leftDepth, rightDepth, time;
        public bool contains;
 
        public Data()
        {
            contains = false;
            leftDepth = rightDepth = 0;
            time = -1;
        }
    }
 
    /*
        Function to calculate time required to burn
        tree completely
         
        node - address of current node
        info - extra information about current node
        target - node that is fired
        res - stores the result
    */
    static void getResult(Node node, Data data,
                            int target)
    {
 
        // Base case: if root is null
        if (node == null)
        {
            return;
        }
 
        // If current node is leaf
        if (node.left == null &&
            node.right == null)
        {
 
            // If current node is the first burnt node
            if (node.data == target)
            {
                data.contains = true;
                data.time = 0;
            }
            return;
        }
 
        // Information about left child
        Data leftData = new Data();
        getResult(node.left, leftData, target);
 
        // Information about right child
        Data rightData = new Data();
        getResult(node.right, rightData, target);
 
        // If left subtree contains the fired node then
        // time required to reach fire to current node
        // will be (1 + time required for left child)
        data.time = (leftData.contains) ?
                    (leftData.time + 1) : -1;
 
        // If right subtree contains the fired node then
        // time required to reach fire to current node
        // will be (1 + time required for right child)
        if (data.time == -1)
            data.time = (rightData.contains) ?
                        (rightData.time + 1) : -1;
 
        // Storing(true or false) if the tree rooted at
        // current node contains the fired node
        data.contains = (leftData.contains ||
                        rightData.contains);
 
        // Calculate the maximum depth of left subtree
        data.leftDepth = (node.left == null) ?
                        0 : (1 + Math.Max(
                        leftData.leftDepth,
                        leftData.rightDepth));
 
        // Calculate the maximum depth of right subtree
        data.rightDepth = (node.right == null) ?
                        0 : (1 + Math.Max(
                        rightData.leftDepth,
                        rightData.rightDepth));
 
        // Calculating answer
        if (data.contains)
        {
 
            // If left subtree exists and
            // it contains the fired node
            if (leftData.contains)
            {
 
                // calculate result
                res = Math.Max(res, data.time +
                                data.rightDepth);
            }
 
            // If right subtree exists and it
            // contains the fired node
            if (rightData.contains)
            {
 
                // calculate result
                res = Math.Max(res, data.time +
                                data.leftDepth);
            }
        }
    }
 
    // To store the result
    public static int res;
 
    // Driver Code
    public static void Main(String []args)
    {
 
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.left.left = new Node(4);
        root.left.right = new Node(5);
        root.right.left = new Node(6);
        root.left.left.left = new Node(8);
        root.left.right.left = new Node(9);
        root.left.right.right = new Node(10);
        root.left.right.left.left = new Node(11);
 
        int target = 11;
 
        res = 0;
        getResult(root, new Data(), target);
        Console.WriteLine(res);
    }
}
 
// This code is contributed by PrinciRaj1992


输出:
6