📜  查找二叉树的最小控制集

📅  最后修改于: 2021-04-24 17:11:15             🧑  作者: Mango

给定具有N个节点的编号为[1,N]的二叉树,任务是找到该树的最小Domination集的大小。

例子:

Input: 
                     1
                    /
                   2
                  / \
                 4   3
               /
              5
            /  \
           6    7
          / \    \
         8   9   10
Output:  3
Explanation: 
Smallest dominating set is {2, 6, 7}

Input: 
                     1
                   /   \
                  2     3
                 / \   / \
                4   5 6   7
               / \   /
              8  9  10
Output:  4
Explanation: 
One of the smallest
dominating set = {2, 3, 6, 4}

方法:
为了解决此问题,我们通过为每个节点定义以下两个状态来使用动态编程方法:

  • 强制性的第一个状态告诉我们是否必须选择集合中的节点。
  • 覆盖的第二个状态,告诉我们节点的父/子是否在集合中。

如果必须选择该节点,则我们选择该节点并将其子节点标记为已覆盖。否则,我们可以选择或拒绝它,然后根据需要更新或不更新其子级。检查每个节点的状态,并相应地找到所需的集合大小。
下面的代码是上述方法的实现:

C++
/* C++ program to find the size of the
minimum dominating set of the tree */
 
#include 
using namespace std;
 
#define N 1005
 
// Definition of a tree node
struct Node {
    int data;
    Node *left, *right;
};
 
/* Helper function that allocates a
new node */
Node* newNode(int data)
{
    Node* node = (Node*)malloc(sizeof(Node));
    node->data = data;
    node->left = node->right = NULL;
    return node;
}
 
// DP array to precompute
// and store the results
int dp[N][5][5];
 
// minDominatingSettion to return the size of
// the minimum dominating set of the array
int minDominatingSet(Node* root, int covered,
                     int compulsory)
{
    // Base case
    if (!root)
        return 0;
 
    // Setting the compulsory value if needed
    if (!root->left and !root->right and !covered)
        compulsory = true;
 
    // Check if the answer is already computed
    if (dp[root->data][covered][compulsory] != -1)
        return dp[root->data][covered][compulsory];
 
    // If it is compulsory to select
    // the node
    if (compulsory) {
        // Choose the node and set its children as covered
        return dp[root->data]
                 [covered]
                 [compulsory]
               = 1
                 + minDominatingSet(
                       root->left, 1, 0)
                 + minDominatingSet(
                       root->right, 1, 0);
    }
 
    // If it is covered
    if (covered) {
        return dp[root->data]
                 [covered]
                 [compulsory]
               = min(
                   1
                       + minDominatingSet(
                             root->left, 1, 0)
                       + minDominatingSet(
                             root->right, 1, 0),
                   minDominatingSet(
                       root->left, 0, 0)
                       + minDominatingSet(
                             root->right, 0, 0));
    }
 
    // If the current node is neither covered nor
    // needs to be selected compulsorily
    int ans = 1
              + minDominatingSet(
                    root->left, 1, 0)
              + minDominatingSet(
                    root->right, 1, 0);
 
    if (root->left) {
        ans = min(ans,
                  minDominatingSet(
                      root->left, 0, 1)
                      + minDominatingSet(
                            root->right, 0, 0));
    }
    if (root->right) {
        ans = min(ans,
                  minDominatingSet(
                      root->left, 0, 0)
                      + minDominatingSet(
                            root->right, 0, 1));
    }
 
    // Store the result
    return dp[root->data]
             [covered]
             [compulsory]
           = ans;
}
 
// Driver code
signed main()
{
    // initialising the DP array
    memset(dp, -1, sizeof(dp));
 
    // Constructing the tree
    Node* root = newNode(1);
    root->left = newNode(2);
    root->left->left = newNode(3);
    root->left->right = newNode(4);
    root->left->left->left = newNode(5);
    root->left->left->left->left = newNode(6);
    root->left->left->left->right = newNode(7);
    root->left->left->left->right->right = newNode(10);
    root->left->left->left->left->left = newNode(8);
    root->left->left->left->left->right = newNode(9);
 
    cout << minDominatingSet(root, 0, 0) << endl;
 
    return 0;
}


Java
// Java program to find the size of the
//minimum dominating set of the tree
import java.util.*;
 
class GFG{
 
static final int N = 1005;
 
// Definition of a tree node
static class Node
{
    int data;
    Node left, right;
};
 
// Helper function that allocates a
// new node
static Node newNode(int data)
{
    Node node = new Node();
    node.data = data;
    node.left = node.right = null;
    return node;
}
 
// DP array to precompute
// and store the results
static int [][][]dp = new int[N][5][5];
 
// minDominatingSettion to return the size of
// the minimum dominating set of the array
static int minDominatingSet(Node root,
                            int covered,
                            int compulsory)
{
    // Base case
    if (root == null)
        return 0;
     
    // Setting the compulsory value if needed
    if (root.left != null &&
       root.right != null &&
       covered > 0)
        compulsory = 1;
 
    // Check if the answer is already computed
    if (dp[root.data][covered][compulsory] != -1)
        return dp[root.data][covered][compulsory];
 
    // If it is compulsory to select
    // the node
    if (compulsory > 0)
    {
         
        // Choose the node and set its
        // children as covered
        return dp[root.data][covered][compulsory] = 1 +
                 minDominatingSet(root.left, 1, 0) +
                 minDominatingSet(root.right, 1, 0);
    }
 
    // If it is covered
    if (covered > 0)
    {
        return dp[root.data][covered]
                 [compulsory] = Math.min(1 +
                  minDominatingSet(root.left, 1, 0) +
                  minDominatingSet(root.right, 1, 0),
                  minDominatingSet(root.left, 0, 0)+
                  minDominatingSet(root.right, 0, 0));
    }
 
    // If the current node is neither covered nor
    // needs to be selected compulsorily
    int ans = 1 + minDominatingSet(root.left, 1, 0) +
                  minDominatingSet(root.right, 1, 0);
 
    if (root.left != null)
    {
        ans = Math.min(ans,
              minDominatingSet(root.left, 0, 1) +
              minDominatingSet(root.right, 0, 0));
    }
    if (root.right != null)
    {
        ans = Math.min(ans,
              minDominatingSet(root.left, 0, 0) +
              minDominatingSet(root.right, 0, 1));
    }
 
    // Store the result
    return dp[root.data][covered][compulsory] = ans;
}
 
// Driver code
public static void main(String[] args)
{
     
    // Initialising the DP array
    for(int i = 0; i < N; i++)
    {
        for(int j = 0; j < 5; j++)
        {
            for(int l = 0; l < 5; l++)
                dp[i][j][l] = -1;
        }
    }
 
    // Constructing the tree
    Node root = newNode(1);
    root.left = newNode(2);
    root.left.left = newNode(3);
    root.left.right = newNode(4);
    root.left.left.left = newNode(5);
    root.left.left.left.left = newNode(6);
    root.left.left.left.right = newNode(7);
    root.left.left.left.right.right = newNode(10);
    root.left.left.left.left.left = newNode(8);
    root.left.left.left.left.right = newNode(9);
 
    System.out.print(minDominatingSet(
        root, 0, 0) + "\n");
}
}
 
// This code is contributed by amal kumar choubey


Python3
# Python3 program to find the size of the
# minimum dominating set of the tree */
N = 1005
  
# Definition of a tree node
class Node:
     
    def __init__(self, data):
         
        self.data = data
        self.left = None
        self.right = None
      
# Helper function that allocates a
# new node
def newNode(data):
 
    node = Node(data)
    return node
  
# DP array to precompute
# and store the results
dp = [[[-1 for i in range(5)] for j in range(5)] for k in range(N)];
  
# minDominatingSettion to return the size of
# the minimum dominating set of the array
def minDominatingSet(root, covered, compulsory):
 
    # Base case
    if (not root):
        return 0;
  
    # Setting the compulsory value if needed
    if (not root.left and not root.right and not covered):
        compulsory = True;
  
    # Check if the answer is already computed
    if (dp[root.data][covered][compulsory] != -1):
        return dp[root.data][covered][compulsory];
  
    # If it is compulsory to select
    # the node
    if (compulsory):
         
        dp[root.data][covered][compulsory] = 1 + minDominatingSet(root.left, 1, 0) + minDominatingSet(root.right, 1, 0);
         
        # Choose the node and set its children as covered
        return dp[root.data][covered][compulsory]
      
    # If it is covered
    if (covered):
        dp[root.data][covered][compulsory] = min(1 + minDominatingSet(root.left, 1, 0) + minDominatingSet(root.right, 1, 0),minDominatingSet(root.left, 0, 0)+ minDominatingSet(root.right, 0, 0));
        return dp[root.data][covered][compulsory]
      
    # If the current node is neither covered nor
    # needs to be selected compulsorily
    ans = 1 + minDominatingSet(root.left, 1, 0) + minDominatingSet(root.right, 1, 0);
  
    if (root.left):
        ans = min(ans, minDominatingSet(root.left, 0, 1) + minDominatingSet(root.right, 0, 0));
     
    if (root.right):
        ans = min(ans, minDominatingSet( root.left, 0, 0) + minDominatingSet(root.right, 0, 1));
      
    # Store the result
    dp[root.data][covered][compulsory]= ans;
    return ans
 
# Driver code
if __name__=='__main__':
      
    # Constructing the tree
    root = newNode(1);
    root.left = newNode(2);
    root.left.left = newNode(3);
    root.left.right = newNode(4);
    root.left.left.left = newNode(5);
    root.left.left.left.left = newNode(6);
    root.left.left.left.right = newNode(7);
    root.left.left.left.right.right = newNode(10);
    root.left.left.left.left.left = newNode(8);
    root.left.left.left.left.right = newNode(9);
  
    print(minDominatingSet(root, 0, 0))
   
  # This code is contributed by rutvik_56


C#
// C# program to find the size of the
//minimum dominating set of the tree
using System;
class GFG{
 
static readonly int N = 1005;
 
// Definition of a tree node
public class Node
{
    public
 int data;
    public
 Node left, right;
};
 
// Helper function that allocates a
// new node
public static Node newNode(int data)
{
    Node node = new Node();
    node.data = data;
    node.left = node.right = null;
    return node;
}
 
// DP array to precompute
// and store the results
static int [,,]dp = new int[N, 5, 5];
 
// minDominatingSettion to return the size of
// the minimum dominating set of the array
static int minDominatingSet(Node root,
                            int covered,
                            int compulsory)
{
    // Base case
    if (root == null)
        return 0;
     
    // Setting the compulsory value if needed
    if (root.left != null &&
       root.right != null &&
       covered > 0)
        compulsory = 1;
 
    // Check if the answer is already computed
    if (dp[root.data, covered, compulsory] != -1)
        return dp[root.data, covered, compulsory];
 
    // If it is compulsory to select
    // the node
    if (compulsory > 0)
    {
         
        // Choose the node and set its
        // children as covered
        return dp[root.data, covered, compulsory] = 1 +
                    minDominatingSet(root.left, 1, 0) +
                   minDominatingSet(root.right, 1, 0);
    }
 
    // If it is covered
    if (covered > 0)
    {
        return dp[root.data, covered, compulsory] = Math.Min(1 +
                             minDominatingSet(root.left, 1, 0) +
                             minDominatingSet(root.right, 1, 0),
                             minDominatingSet(root.left, 0, 0)+
                            minDominatingSet(root.right, 0, 0));
    }
 
    // If the current node is neither covered nor
    // needs to be selected compulsorily
    int ans = 1 + minDominatingSet(root.left, 1, 0) +
                  minDominatingSet(root.right, 1, 0);
 
    if (root.left != null)
    {
        ans = Math.Min(ans,
              minDominatingSet(root.left, 0, 1) +
              minDominatingSet(root.right, 0, 0));
    }
    if (root.right != null)
    {
        ans = Math.Min(ans,
              minDominatingSet(root.left, 0, 0) +
              minDominatingSet(root.right, 0, 1));
    }
 
    // Store the result
    return dp[root.data, covered, compulsory] = ans;
}
 
// Driver code
public static void Main(String[] args)
{
     
    // Initialising the DP array
    for(int i = 0; i < N; i++)
    {
        for(int j = 0; j < 5; j++)
        {
            for(int l = 0; l < 5; l++)
                dp[i, j, l] = -1;
        }
    }
 
    // Constructing the tree
    Node root = newNode(1);
    root.left = newNode(2);
    root.left.left = newNode(3);
    root.left.right = newNode(4);
    root.left.left.left = newNode(5);
    root.left.left.left.left = newNode(6);
    root.left.left.left.right = newNode(7);
    root.left.left.left.right.right = newNode(10);
    root.left.left.left.left.left = newNode(8);
    root.left.left.left.left.right = newNode(9);
 
    Console.Write(minDominatingSet
                  root, 0, 0) + "\n");
}
}
 
// This code is contributed by Rohit_ranjan


输出:
3

时间复杂度: O(N * log N)