无向图的顶点覆盖是其顶点的子集,因此对于图的每个边(u,v),“ u”或“ v”都在顶点覆盖中。尽管名称为“顶点覆盖”,但该集合覆盖了给定图形的所有边缘。
寻找图形的最小尺寸顶点覆盖的问题是NP完整的。但这可以在树的多项式时间内解决。在这篇文章中,讨论了二叉树的解决方案。相同的解决方案可以扩展到n元树。
例如,考虑下面的二叉树。最小的顶点覆盖为{20,50,30},顶点覆盖的大小为3。
想法是考虑为根遵循以下两种可能性,并为根向下的所有节点递归地遵循以下两种可能性。
1)根是顶点覆盖的一部分:在这种情况下,根覆盖所有子边缘。我们递归地计算左右子树的顶点覆盖大小,并将结果加1(对于根)。
2)根不是顶点覆盖的一部分:在这种情况下,必须将两个根的子代都包括在顶点覆盖中,以覆盖所有根到子边缘。我们递归计算所有孙子代的顶点覆盖大小和结果的子代数(对于两个根的子代)。
以下是上述想法的实现。
C
// A naive recursive C implementation for vertex cover problem for a tree
#include
#include
// A utility function to find min of two integers
int min(int x, int y) { return (x < y)? x: y; }
/* A binary tree node has data, pointer to left child and a pointer to
right child */
struct node
{
int data;
struct node *left, *right;
};
// The function returns size of the minimum vertex cover
int vCover(struct node *root)
{
// The size of minimum vertex cover is zero if tree is empty or there
// is only one node
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 0;
// Calculate size of vertex cover when root is part of it
int size_incl = 1 + vCover(root->left) + vCover(root->right);
// Calculate size of vertex cover when root is not part of it
int size_excl = 0;
if (root->left)
size_excl += 1 + vCover(root->left->left) + vCover(root->left->right);
if (root->right)
size_excl += 1 + vCover(root->right->left) + vCover(root->right->right);
// Return the minimum of two sizes
return min(size_incl, size_excl);
}
// A utility function to create a node
struct node* newNode( int data )
{
struct node* temp = (struct node *) malloc( sizeof(struct node) );
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
// Driver program to test above functions
int main()
{
// Let us construct the tree given in the above diagram
struct node *root = newNode(20);
root->left = newNode(8);
root->left->left = newNode(4);
root->left->right = newNode(12);
root->left->right->left = newNode(10);
root->left->right->right = newNode(14);
root->right = newNode(22);
root->right->right = newNode(25);
printf ("Size of the smallest vertex cover is %d ", vCover(root));
return 0;
}
Java
// A naive recursive Java implementation
// for vertex cover problem for a tree
class GFG
{
// A utility function to find min of two integers
static int min(int x, int y)
{
return (x < y) ? x : y;
}
/*
* A binary tree node has data, pointer
to left child and a pointer to right
* child
*/
static class node
{
int data;
node left, right;
};
// The function returns size
// of the minimum vertex cover
static int vCover(node root)
{
// The size of minimum vertex cover
// is zero if tree is empty or there
// is only one node
if (root == null)
return 0;
if (root.left == null && root.right == null)
return 0;
// Calculate size of vertex cover
// when root is part of it
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
// Calculate size of vertex cover
// when root is not part of it
int size_excl = 0;
if (root.left != null)
size_excl += 1 + vCover(root.left.left) +
vCover(root.left.right);
if (root.right != null)
size_excl += 1 + vCover(root.right.left) +
vCover(root.right.right);
// Return the minimum of two sizes
return Math.min(size_incl, size_excl);
}
// A utility function to create a node
static node newNode(int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null;
return temp;
}
// Driver code
public static void main(String[] args)
{
// Let us conthe tree given in the above diagram
node root = newNode(20);
root.left = newNode(8);
root.left.left = newNode(4);
root.left.right = newNode(12);
root.left.right.left = newNode(10);
root.left.right.right = newNode(14);
root.right = newNode(22);
root.right.right = newNode(25);
System.out.printf("Size of the smallest vertex" +
"cover is %d ", vCover(root));
}
}
// This code is contributed by 29AjayKumar
Python3
# A naive recursive Python3 implementation
# for vertex cover problem for a tree
# A utility function to find min of two integers
# A binary tree node has data, pointer to
# left child and a pointer to right child
class Node:
def __init__(self, x):
self.data = x
self.left = None
self.right = None
# The function returns size of
# the minimum vertex cover
def vCover(root):
# The size of minimum vertex cover
# is zero if tree is empty or there
# is only one node
if (root == None):
return 0
if (root.left == None and
root.right == None):
return 0
# Calculate size of vertex cover when
# root is part of it
size_incl = (1 + vCover(root.left) +
vCover(root.right))
# Calculate size of vertex cover
# when root is not part of it
size_excl = 0
if (root.left):
size_excl += (1 + vCover(root.left.left) +
vCover(root.left.right))
if (root.right):
size_excl += (1 + vCover(root.right.left) +
vCover(root.right.right))
# Return the minimum of two sizes
return min(size_incl, size_excl)
# Driver Code
if __name__ == '__main__':
# Let us construct the tree
# given in the above diagram
root = Node(20)
root.left = Node(8)
root.left.left = Node(4)
root.left.right = Node(12)
root.left.right.left = Node(10)
root.left.right.right = Node(14)
root.right = Node(22)
root.right.right = Node(25)
print("Size of the smallest vertex cover is", vCover(root))
# This code is contributed by mohit kumar 29
C#
// A naive recursive C# implementation
// for vertex cover problem for a tree
using System;
class GFG
{
// A utility function to find
// min of two integers
static int min(int x, int y)
{
return (x < y) ? x : y;
}
/*
* A binary tree node has data, pointer
to left child and a pointer to right
* child
*/
public class node
{
public int data;
public node left, right;
};
// The function returns size
// of the minimum vertex cover
static int vCover(node root)
{
// The size of minimum vertex cover
// is zero if tree is empty or there
// is only one node
if (root == null)
return 0;
if (root.left == null &&
root.right == null)
return 0;
// Calculate size of vertex cover
// when root is part of it
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
// Calculate size of vertex cover
// when root is not part of it
int size_excl = 0;
if (root.left != null)
size_excl += 1 + vCover(root.left.left) +
vCover(root.left.right);
if (root.right != null)
size_excl += 1 + vCover(root.right.left) +
vCover(root.right.right);
// Return the minimum of two sizes
return Math.Min(size_incl, size_excl);
}
// A utility function to create a node
static node newNode(int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null;
return temp;
}
// Driver code
public static void Main(String[] args)
{
// Let us conthe tree given
// in the above diagram
node root = newNode(20);
root.left = newNode(8);
root.left.left = newNode(4);
root.left.right = newNode(12);
root.left.right.left = newNode(10);
root.left.right.right = newNode(14);
root.right = newNode(22);
root.right.right = newNode(25);
Console.Write("Size of the smallest vertex" +
"cover is {0} ", vCover(root));
}
}
// This code is contributed by 29AjayKumar
C
/* Dynamic programming based program for Vertex Cover problem for
a Binary Tree */
#include
#include
// A utility function to find min of two integers
int min(int x, int y) { return (x < y)? x: y; }
/* A binary tree node has data, pointer to left child and a pointer to
right child */
struct node
{
int data;
int vc;
struct node *left, *right;
};
// A memoization based function that returns size of the minimum vertex cover.
int vCover(struct node *root)
{
// The size of minimum vertex cover is zero if tree is empty or there
// is only one node
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 0;
// If vertex cover for this node is already evaluated, then return it
// to save recomputation of same subproblem again.
if (root->vc != 0)
return root->vc;
// Calculate size of vertex cover when root is part of it
int size_incl = 1 + vCover(root->left) + vCover(root->right);
// Calculate size of vertex cover when root is not part of it
int size_excl = 0;
if (root->left)
size_excl += 1 + vCover(root->left->left) + vCover(root->left->right);
if (root->right)
size_excl += 1 + vCover(root->right->left) + vCover(root->right->right);
// Minimum of two values is vertex cover, store it before returning
root->vc = min(size_incl, size_excl);
return root->vc;
}
// A utility function to create a node
struct node* newNode( int data )
{
struct node* temp = (struct node *) malloc( sizeof(struct node) );
temp->data = data;
temp->left = temp->right = NULL;
temp->vc = 0; // Set the vertex cover as 0
return temp;
}
// Driver program to test above functions
int main()
{
// Let us construct the tree given in the above diagram
struct node *root = newNode(20);
root->left = newNode(8);
root->left->left = newNode(4);
root->left->right = newNode(12);
root->left->right->left = newNode(10);
root->left->right->right = newNode(14);
root->right = newNode(22);
root->right->right = newNode(25);
printf ("Size of the smallest vertex cover is %d ", vCover(root));
return 0;
}
Java
/* Dynamic programming based program for
Vertex Cover problem for a Binary Tree */
class GFG
{
// A utility function to find min of two integers
static int min(int x, int y)
{
return (x < y) ? x : y;
}
/*
* A binary tree node has data, pointer
to left child and a pointer to right
* child
*/
static class node
{
int data;
int vc;
node left, right;
};
// A memoization based function that returns
// size of the minimum vertex cover.
static int vCover(node root)
{
// The size of minimum vertex cover is zero
// if tree is empty or there is only one node
if (root == null)
return 0;
if (root.left == null && root.right == null)
return 0;
// If vertex cover for this node is
// already evaluated, then return it
// to save recomputation of same subproblem again.
if (root.vc != 0)
return root.vc;
// Calculate size of vertex cover
// when root is part of it
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
// Calculate size of vertex cover
// when root is not part of it
int size_excl = 0;
if (root.left != null)
size_excl += 1 + vCover(root.left.left) +
vCover(root.left.right);
if (root.right != null)
size_excl += 1 + vCover(root.right.left) +
vCover(root.right.right);
// Minimum of two values is vertex cover,
// store it before returning
root.vc = Math.min(size_incl, size_excl);
return root.vc;
}
// A utility function to create a node
static node newNode(int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null;
temp.vc = 0; // Set the vertex cover as 0
return temp;
}
// Driver code
public static void main(String[] args)
{
// Let us conthe tree given in the above diagram
node root = newNode(20);
root.left = newNode(8);
root.left.left = newNode(4);
root.left.right = newNode(12);
root.left.right.left = newNode(10);
root.left.right.right = newNode(14);
root.right = newNode(22);
root.right.right = newNode(25);
System.out.printf("Size of the smallest vertex" +
"cover is %d ", vCover(root));
}
}
// This code is contributed by PrinciRaj1992
C#
/* Dynamic programming based program for
Vertex Cover problem for a Binary Tree */
using System;
class GFG
{
// A utility function to find
// min of two integers
static int min(int x, int y)
{
return (x < y) ? x : y;
}
/*
* A binary tree node has data, pointer
to left child and a pointer to right
* child
*/
class node
{
public int data;
public int vc;
public node left, right;
};
// A memoization based function that returns
// size of the minimum vertex cover.
static int vCover(node root)
{
// The size of minimum vertex cover is zero
// if tree is empty or there is only one node
if (root == null)
return 0;
if (root.left == null &&
root.right == null)
return 0;
// If vertex cover for this node is
// already evaluated, then return it
// to save recomputation of same subproblem again.
if (root.vc != 0)
return root.vc;
// Calculate size of vertex cover
// when root is part of it
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
// Calculate size of vertex cover
// when root is not part of it
int size_excl = 0;
if (root.left != null)
size_excl += 1 + vCover(root.left.left) +
vCover(root.left.right);
if (root.right != null)
size_excl += 1 + vCover(root.right.left) +
vCover(root.right.right);
// Minimum of two values is vertex cover,
// store it before returning
root.vc = Math.Min(size_incl, size_excl);
return root.vc;
}
// A utility function to create a node
static node newNode(int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null;
temp.vc = 0; // Set the vertex cover as 0
return temp;
}
// Driver code
public static void Main(String[] args)
{
// Let us conthe tree given in the above diagram
node root = newNode(20);
root.left = newNode(8);
root.left.left = newNode(4);
root.left.right = newNode(12);
root.left.right.left = newNode(10);
root.left.right.right = newNode(14);
root.right = newNode(22);
root.right.right = newNode(25);
Console.Write("Size of the smallest vertex" +
"cover is {0} ", vCover(root));
}
}
// This code is contributed by PrinciRaj1992
输出:
Size of the smallest vertex cover is 3
上述幼稚递归方法的时间复杂度是指数的。应该注意的是,上述函数一次又一次地计算相同的子问题。例如,值为50的节点的vCover评估两次,因为50的孙子为10,子项为20。
由于再次调用了相同的问题,因此此问题具有“重叠子问题”属性。因此,“顶点覆盖”问题具有动态编程问题的两个属性(请参阅此内容)。像其他典型的动态规划(DP)问题一样,可以通过存储子问题的解决方案并以自下而上的方式解决问题,避免相同子问题的重新计算。
以下是基于动态编程的解决方案的实现。在以下解决方案中,一个附加字段’vc’被添加到树节点。对于所有节点,“ vc”的初始值均设置为0。递归函数vCover()仅在尚未设置节点时才为其计算“ vc”。
C
/* Dynamic programming based program for Vertex Cover problem for
a Binary Tree */
#include
#include
// A utility function to find min of two integers
int min(int x, int y) { return (x < y)? x: y; }
/* A binary tree node has data, pointer to left child and a pointer to
right child */
struct node
{
int data;
int vc;
struct node *left, *right;
};
// A memoization based function that returns size of the minimum vertex cover.
int vCover(struct node *root)
{
// The size of minimum vertex cover is zero if tree is empty or there
// is only one node
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 0;
// If vertex cover for this node is already evaluated, then return it
// to save recomputation of same subproblem again.
if (root->vc != 0)
return root->vc;
// Calculate size of vertex cover when root is part of it
int size_incl = 1 + vCover(root->left) + vCover(root->right);
// Calculate size of vertex cover when root is not part of it
int size_excl = 0;
if (root->left)
size_excl += 1 + vCover(root->left->left) + vCover(root->left->right);
if (root->right)
size_excl += 1 + vCover(root->right->left) + vCover(root->right->right);
// Minimum of two values is vertex cover, store it before returning
root->vc = min(size_incl, size_excl);
return root->vc;
}
// A utility function to create a node
struct node* newNode( int data )
{
struct node* temp = (struct node *) malloc( sizeof(struct node) );
temp->data = data;
temp->left = temp->right = NULL;
temp->vc = 0; // Set the vertex cover as 0
return temp;
}
// Driver program to test above functions
int main()
{
// Let us construct the tree given in the above diagram
struct node *root = newNode(20);
root->left = newNode(8);
root->left->left = newNode(4);
root->left->right = newNode(12);
root->left->right->left = newNode(10);
root->left->right->right = newNode(14);
root->right = newNode(22);
root->right->right = newNode(25);
printf ("Size of the smallest vertex cover is %d ", vCover(root));
return 0;
}
Java
/* Dynamic programming based program for
Vertex Cover problem for a Binary Tree */
class GFG
{
// A utility function to find min of two integers
static int min(int x, int y)
{
return (x < y) ? x : y;
}
/*
* A binary tree node has data, pointer
to left child and a pointer to right
* child
*/
static class node
{
int data;
int vc;
node left, right;
};
// A memoization based function that returns
// size of the minimum vertex cover.
static int vCover(node root)
{
// The size of minimum vertex cover is zero
// if tree is empty or there is only one node
if (root == null)
return 0;
if (root.left == null && root.right == null)
return 0;
// If vertex cover for this node is
// already evaluated, then return it
// to save recomputation of same subproblem again.
if (root.vc != 0)
return root.vc;
// Calculate size of vertex cover
// when root is part of it
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
// Calculate size of vertex cover
// when root is not part of it
int size_excl = 0;
if (root.left != null)
size_excl += 1 + vCover(root.left.left) +
vCover(root.left.right);
if (root.right != null)
size_excl += 1 + vCover(root.right.left) +
vCover(root.right.right);
// Minimum of two values is vertex cover,
// store it before returning
root.vc = Math.min(size_incl, size_excl);
return root.vc;
}
// A utility function to create a node
static node newNode(int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null;
temp.vc = 0; // Set the vertex cover as 0
return temp;
}
// Driver code
public static void main(String[] args)
{
// Let us conthe tree given in the above diagram
node root = newNode(20);
root.left = newNode(8);
root.left.left = newNode(4);
root.left.right = newNode(12);
root.left.right.left = newNode(10);
root.left.right.right = newNode(14);
root.right = newNode(22);
root.right.right = newNode(25);
System.out.printf("Size of the smallest vertex" +
"cover is %d ", vCover(root));
}
}
// This code is contributed by PrinciRaj1992
C#
/* Dynamic programming based program for
Vertex Cover problem for a Binary Tree */
using System;
class GFG
{
// A utility function to find
// min of two integers
static int min(int x, int y)
{
return (x < y) ? x : y;
}
/*
* A binary tree node has data, pointer
to left child and a pointer to right
* child
*/
class node
{
public int data;
public int vc;
public node left, right;
};
// A memoization based function that returns
// size of the minimum vertex cover.
static int vCover(node root)
{
// The size of minimum vertex cover is zero
// if tree is empty or there is only one node
if (root == null)
return 0;
if (root.left == null &&
root.right == null)
return 0;
// If vertex cover for this node is
// already evaluated, then return it
// to save recomputation of same subproblem again.
if (root.vc != 0)
return root.vc;
// Calculate size of vertex cover
// when root is part of it
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
// Calculate size of vertex cover
// when root is not part of it
int size_excl = 0;
if (root.left != null)
size_excl += 1 + vCover(root.left.left) +
vCover(root.left.right);
if (root.right != null)
size_excl += 1 + vCover(root.right.left) +
vCover(root.right.right);
// Minimum of two values is vertex cover,
// store it before returning
root.vc = Math.Min(size_incl, size_excl);
return root.vc;
}
// A utility function to create a node
static node newNode(int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null;
temp.vc = 0; // Set the vertex cover as 0
return temp;
}
// Driver code
public static void Main(String[] args)
{
// Let us conthe tree given in the above diagram
node root = newNode(20);
root.left = newNode(8);
root.left.left = newNode(4);
root.left.right = newNode(12);
root.left.right.left = newNode(10);
root.left.right.right = newNode(14);
root.right = newNode(22);
root.right.right = newNode(25);
Console.Write("Size of the smallest vertex" +
"cover is {0} ", vCover(root));
}
}
// This code is contributed by PrinciRaj1992
输出:
Size of the smallest vertex cover is 3