给定具有N个节点的编号为[1,N]的二叉树,任务是找到该树的最小Domination集的大小。
A set of nodes is said to be a dominating node if every node in the binary tree not present in the set is an immediate child/parent to any node in that set.
例子:
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)