A vertex cover of an undirected graph is a subset of its vertices such that for every edge (u, v) of the graph, either ‘u’ or ‘v’ is in vertex cover. Although the name is Vertex Cover, the set covers all edges of the given graph.
The problem to find minimum size vertex cover of a graph is NP complete. But it can be solved in polynomial time for trees. In this post a solution for Binary Tree is discussed. The same solution can be extended for n-ary trees.
For example, consider the following binary tree. The smallest vertex cover is {20, 50, 30} and size of the vertex cover is 3.

The idea is to consider following two possibilities for root and recursively for all nodes down the root.
1) Root is part of vertex cover: In this case root covers all children edges. We recursively calculate size of vertex covers for left and right subtrees and add 1 to the result (for root).
2) Root is not part of vertex cover: In this case, both children of root must be included in vertex cover to cover all root to children edges. We recursively calculate size of vertex covers of all grandchildren and number of children to the result (for two children of root).
Below are implementation of above idea.
C
#include <stdio.h>
#include <stdlib.h>
int min( int x, int y) { return (x < y)? x: y; }
struct node
{
int data;
struct node *left, *right;
};
int vCover( struct node *root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 0;
int size_incl = 1 + vCover(root->left) + vCover(root->right);
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 min(size_incl, size_excl);
}
struct node* newNode( int data )
{
struct node* temp = ( struct node *) malloc ( sizeof ( struct node) );
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
int main()
{
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;
}
|
C++
#include <iostream>
#include <cstdlib>
int min( int x, int y) { return (x < y)? x: y; }
struct node
{
int data;
node *left, *right;
};
int vCover(node *root)
{
if (root == nullptr)
return 0;
if (root->left == nullptr && root->right == nullptr)
return 0;
int size_incl = 1 + vCover(root->left) + vCover(root->right);
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 min(size_incl, size_excl);
}
node* newNode( int data )
{
node* temp = new node;
temp->data = data;
temp->left = temp->right = nullptr;
return temp;
}
int main()
{
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);
std::cout << "Size of the smallest vertex cover is " << vCover(root) << std::endl;
return 0;
}
|
Java
class GFG
{
static int min( int x, int y)
{
return (x < y) ? x : y;
}
static class node
{
int data;
node left, right;
};
static int vCover(node root)
{
if (root == null )
return 0 ;
if (root.left == null && root.right == null )
return 0 ;
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
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 Math.min(size_incl, size_excl);
}
static node newNode( int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null ;
return temp;
}
public static void main(String[] args)
{
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));
}
}
|
Python3
class Node:
def __init__( self , x):
self .data = x
self .left = None
self .right = None
def vCover(root):
if (root = = None ):
return 0
if (root.left = = None and
root.right = = None ):
return 0
size_incl = ( 1 + vCover(root.left) +
vCover(root.right))
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 min (size_incl, size_excl)
if __name__ = = '__main__' :
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))
|
C#
using System;
class GFG
{
static int min( int x, int y)
{
return (x < y) ? x : y;
}
public class node
{
public int data;
public node left, right;
};
static int vCover(node root)
{
if (root == null )
return 0;
if (root.left == null &&
root.right == null )
return 0;
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
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 Math.Min(size_incl, size_excl);
}
static node newNode( int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null ;
return temp;
}
public static void Main(String[] args)
{
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));
}
}
|
Javascript
<script>
function min(x,y)
{
return (x < y) ? x : y;
}
class Node
{
constructor(d)
{
this .data=d;
this .left= null ;
this .right= null ;
}
}
function vCover(root)
{
if (root == null )
return 0;
if (root.left == null && root.right == null )
return 0;
let size_incl = 1 + vCover(root.left) +
vCover(root.right);
let 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 Math.min(size_incl, size_excl);
}
root = new Node(20);
root.left = new Node(8);
root.left.left = new Node(4);
root.left.right = new Node(12);
root.left.right.left = new Node(10);
root.left.right.right = new Node(14);
root.right = new Node(22);
root.right.right = new Node(25);
document.write( "Size of the smallest vertex" +
"cover is " , vCover(root));
</script>
|
Output
Size of the smallest vertex cover is 3
Time complexity of the above naive recursive approach is exponential. It should be noted that the above function computes the same subproblems again and again. For example, vCover of node with value 50 is evaluated twice as 50 is grandchild of 10 and child of 20.
Since same subproblems are called again, this problem has Overlapping Subproblems property. So Vertex Cover problem has both properties (see this and this) of a dynamic programming problem. Like other typical Dynamic Programming(DP) problems, re-computations of same subproblems can be avoided by storing the solutions to subproblems and solving problems in bottom up manner.
Following is the implementation of Dynamic Programming based solution. In the following solution, an additional field ‘vc’ is added to tree nodes. The initial value of ‘vc’ is set as 0 for all nodes. The recursive function vCover() calculates ‘vc’ for a node only if it is not already set.
C
#include <stdio.h>
#include <stdlib.h>
int min( int x, int y) { return (x < y)? x: y; }
struct node
{
int data;
int vc;
struct node *left, *right;
};
int vCover( struct node *root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 0;
if (root->vc != 0)
return root->vc;
int size_incl = 1 + vCover(root->left) + vCover(root->right);
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);
root->vc = min(size_incl, size_excl);
return root->vc;
}
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;
return temp;
}
int main()
{
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;
}
|
C++
#include <iostream>
#include <stdlib.h>
int min( int x, int y) { return (x < y)? x: y; }
struct node
{
int data;
int vc;
struct node *left, *right;
};
int vCover( struct node *root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 0;
if (root->vc != 0)
return root->vc;
int size_incl = 1 + vCover(root->left) + vCover(root->right);
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);
root->vc = min(size_incl, size_excl);
return root->vc;
}
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;
return temp;
}
int main()
{
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);
std::cout << "Size of the smallest vertex cover is " << vCover(root) << std::endl;
return 0;
}
|
Java
class GFG
{
static int min( int x, int y)
{
return (x < y) ? x : y;
}
static class node
{
int data;
int vc;
node left, right;
};
static int vCover(node root)
{
if (root == null )
return 0 ;
if (root.left == null && root.right == null )
return 0 ;
if (root.vc != 0 )
return root.vc;
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
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);
root.vc = Math.min(size_incl, size_excl);
return root.vc;
}
static node newNode( int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null ;
temp.vc = 0 ;
return temp;
}
public static void main(String[] args)
{
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));
}
}
|
C#
using System;
class GFG
{
static int min( int x, int y)
{
return (x < y) ? x : y;
}
class node
{
public int data;
public int vc;
public node left, right;
};
static int vCover(node root)
{
if (root == null )
return 0;
if (root.left == null &&
root.right == null )
return 0;
if (root.vc != 0)
return root.vc;
int size_incl = 1 + vCover(root.left) +
vCover(root.right);
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);
root.vc = Math.Min(size_incl, size_excl);
return root.vc;
}
static node newNode( int data)
{
node temp = new node();
temp.data = data;
temp.left = temp.right = null ;
temp.vc = 0;
return temp;
}
public static void Main(String[] args)
{
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));
}
}
|
Javascript
<script>
function min(x,y)
{
return (x < y) ? x : y;
}
class Node
{
constructor(data)
{
this .vc=0;
this .data=data;
this .left= this .right= null ;
}
}
function vCover(root)
{
if (root == null )
return 0;
if (root.left == null && root.right == null )
return 0;
if (root.vc != 0)
return root.vc;
let size_incl = 1 + vCover(root.left) +
vCover(root.right);
let 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);
root.vc = Math.min(size_incl, size_excl);
return root.vc;
}
let root = new Node(20);
root.left = new Node(8);
root.left.left = new Node(4);
root.left.right = new Node(12);
root.left.right.left = new Node(10);
root.left.right.right = new Node(14);
root.right = new Node(22);
root.right.right = new Node(25);
document.write( "Size of the smallest vertex " +
"cover is " , vCover(root));
</script>
|
Python3
class node:
def __init__( self ):
self .data = 0
self .vc = 0
self .left = None
self .right = None
def main():
root = Globals .newNode( 20 )
root.left = Globals .newNode( 8 )
root.left.left = Globals .newNode( 4 )
root.left.right = Globals .newNode( 12 )
root.left.right.left = Globals .newNode( 10 )
root.left.right.right = Globals .newNode( 14 )
root.right = Globals .newNode( 22 )
root.right.right = Globals .newNode( 25 )
print ( "Size of the smallest vertex cover is " , end = '')
print ( Globals .vCover(root), end = '')
print ( "\n" , end = '')
class Globals :
@staticmethod
def min (x, y):
if (x < y):
return x
else :
return y
@staticmethod
def vCover(root):
if root is None :
return 0
if root.left is None and root.right is None :
return 0
if root.vc ! = 0 :
return root.vc
size_incl = 1 + Globals .vCover(root.left) + Globals .vCover(root.right)
size_excl = 0
if root.left:
size_excl + = 1 + \
Globals .vCover(root.left.left) + \
Globals .vCover(root.left.right)
if root.right:
size_excl + = 1 + \
Globals .vCover(root.right.left) + \
Globals .vCover(root.right.right)
root.vc = Globals . min (size_incl, size_excl)
return root.vc
@staticmethod
def newNode(data):
temp = node()
temp.data = data
temp.left = temp.right = None
temp.vc = 0
return temp
if __name__ = = "__main__" :
main()
|
Output
Size of the smallest vertex cover is 3
Time Complexity:
The time complexity of the vCover function is O(n), where n is the number of nodes in the binary tree. This is because each node is visited only once and its vertex cover size is calculated in constant time.
Space Complexity:
The space complexity of the program is O(n), where n is the number of nodes in the binary tree. This is because the space required for the binary tree is proportional to the number of nodes in the tree. Additionally, the memoization technique used in the vCover function requires additional space to store the vertex cover sizes of already evaluated nodes. However, since the depth of the recursion tree is limited by the height of the binary tree, the space complexity of the program is also O(h), where h is the height of the binary tree. In the worst case scenario where the binary tree is skewed, the height of the tree can be as large as n, which would result in a space complexity of O(n).
References:
http://courses.csail.mit.edu/6.006/spring11/lectures/lec21.pdf
Exercise:
Extend the above solution for n-ary trees.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above
Approach for any general tree :
1. Approach will be same dynamic programming approach as discussed.
2. For every node, if we exclude this node from vertex cover than we have to include its neighbouring nodes,
and if we include this node in the vertex cover than we will take the minimum of the two possibilities of taking its neighbouring
nodes in the vertex cover to get minimum vertex cover.
3. We will store the above information in the dp array.
C++
#include <bits/stdc++.h>
using namespace std;
void addEdge(vector< int > adj[], int x, int y)
{
adj[x].push_back(y);
adj[y].push_back(x);
}
void dfs(vector< int > adj[], vector< int > dp[], int src,
int par)
{
for ( auto child : adj[src]) {
if (child != par)
dfs(adj, dp, child, src);
}
for ( auto child : adj[src]) {
if (child != par) {
dp[src][0] += dp[child][1];
dp[src][1] += min(dp[child][1], dp[child][0]);
}
}
}
void minSizeVertexCover(vector< int > adj[], int N)
{
vector< int > dp[N + 1];
for ( int i = 1; i <= N; i++) {
dp[i].push_back(0);
dp[i].push_back(1);
}
dfs(adj, dp, 1, -1);
cout << min(dp[1][0], dp[1][1]) << endl;
}
int main()
{
int N = 8;
vector< int > adj[N + 1];
addEdge(adj, 1, 2);
addEdge(adj, 1, 7);
addEdge(adj, 2, 3);
addEdge(adj, 2, 6);
addEdge(adj, 3, 4);
addEdge(adj, 3, 8);
addEdge(adj, 3, 5);
minSizeVertexCover(adj, N);
return 0;
}
|
Java
import java.util.*;
class GFG {
static void addEdge(List<List<Integer> > adj, int x,
int y)
{
adj.get(x).add(y);
adj.get(y).add(x);
}
static void dfs(List<List<Integer> > adj,
List<List<Integer> > dp, int src,
int par)
{
for (Integer child : adj.get(src)) {
if (child != par)
dfs(adj, dp, child, src);
}
for (Integer child : adj.get(src)) {
if (child != par) {
dp.get(src).set( 0 ,
dp.get(child).get( 1 )
+ dp.get(src).get( 0 ));
dp.get(src).set(
1 ,
dp.get(src).get( 1 )
+ Math.min(dp.get(child).get( 1 ),
dp.get(child).get( 0 )));
}
}
}
static void minSizeVertexCover(List<List<Integer> > adj,
int N)
{
List<List<Integer> > dp = new ArrayList<>();
for ( int i = 0 ; i <= N; i++) {
dp.add( new ArrayList<>());
}
for ( int i = 1 ; i <= N; i++) {
dp.get(i).add( 0 );
dp.get(i).add( 1 );
}
dfs(adj, dp, 1 , - 1 );
System.out.println(
Math.min(dp.get( 1 ).get( 0 ), dp.get( 1 ).get( 1 )));
}
public static void main(String[] args)
{
int N = 8 ;
List<List<Integer> > adj = new ArrayList<>();
for ( int i = 0 ; i <= N; i++) {
adj.add( new ArrayList<>());
}
addEdge(adj, 1 , 2 );
addEdge(adj, 1 , 7 );
addEdge(adj, 2 , 3 );
addEdge(adj, 2 , 6 );
addEdge(adj, 3 , 4 );
addEdge(adj, 3 , 8 );
addEdge(adj, 3 , 5 );
minSizeVertexCover(adj, N);
}
}
|
Python3
def addEdge(adj, x, y):
adj[x].append(y)
adj[y].append(x)
def dfs(adj, dp, src, par):
for child in adj[src]:
if child ! = par:
dfs(adj, dp, child, src)
for child in adj[src]:
if child ! = par:
dp[src][ 0 ] = dp[child][ 1 ] + dp[src][ 0 ]
dp[src][ 1 ] = dp[src][ 1 ] + min (dp[child][ 1 ], dp[child][ 0 ])
def minSizeVertexCover(adj, N):
dp = [[ 0 for j in range ( 2 )] for i in range (N + 1 )]
for i in range ( 1 , N + 1 ):
dp[i][ 0 ] = 0
dp[i][ 1 ] = 1
dfs(adj, dp, 1 , - 1 )
print ( min (dp[ 1 ][ 0 ], dp[ 1 ][ 1 ]))
N = 8
adj = [[] for i in range (N + 1 )]
addEdge(adj, 1 , 2 )
addEdge(adj, 1 , 7 )
addEdge(adj, 2 , 3 )
addEdge(adj, 2 , 6 )
addEdge(adj, 3 , 4 )
addEdge(adj, 3 , 8 )
addEdge(adj, 3 , 5 )
minSizeVertexCover(adj, N)
|
C#
using System;
using System.Collections.Generic;
class GFG
{
static void addEdge(List<List< int >> adj, int x, int y)
{
adj[x].Add(y);
adj[y].Add(x);
}
static void dfs(List<List< int >> adj, List<List< int >> dp, int src, int par)
{
foreach ( int child in adj[src])
{
if (child != par)
dfs(adj, dp, child, src);
}
foreach ( int child in adj[src])
{
if (child != par)
{
dp[src][0] = dp[child][1] + dp[src][0];
dp[src][1] = dp[src][1] + Math.Min(dp[child][1], dp[child][0]);
}
}
}
static void minSizeVertexCover(List<List< int >> adj, int N)
{
List<List< int >> dp = new List<List< int >>();
for ( int i = 0; i <= N; i++)
{
dp.Add( new List< int >());
}
for ( int i = 1; i <= N; i++)
{
dp[i].Add(0);
dp[i].Add(1);
}
dfs(adj, dp, 1, -1);
Console.WriteLine(Math.Min(dp[1][0], dp[1][1]));
}
public static void Main( string [] args)
{
int N = 8;
List<List< int >> adj = new List<List< int >>();
for ( int i = 0; i <= N; i++)
{
adj.Add( new List< int >());
}
addEdge(adj, 1, 2);
addEdge(adj, 1, 7);
addEdge(adj, 2, 3);
addEdge(adj, 2, 6);
addEdge(adj, 3, 4);
addEdge(adj, 3, 8);
addEdge(adj, 3, 5);
minSizeVertexCover(adj, N);
}
}
|
Javascript
function addEdge(adj, x, y) {
adj[x].push(y);
adj[y].push(x);
}
function dfs(adj, dp, src, par) {
for (let child of adj[src]) {
if (child != par) dfs(adj, dp, child, src);
}
for (let child of adj[src]) {
if (child != par) {
dp[src][0] += dp[child][1];
dp[src][1] += Math.min(dp[child][1], dp[child][0]);
}
}
}
function minSizeVertexCover(adj, N) {
let dp = Array.from(Array(N + 1), () => new Array());
for ( var i = 1; i <= N; i++) {
dp[i].push(0);
dp[i].push(1);
}
dfs(adj, dp, 1, -1);
console.log(Math.min(dp[1][0], dp[1][1]));
}
var N = 8;
let adj = Array.from(Array(N + 1), () => new Array());
addEdge(adj, 1, 2);
addEdge(adj, 1, 7);
addEdge(adj, 2, 3);
addEdge(adj, 2, 6);
addEdge(adj, 3, 4);
addEdge(adj, 3, 8);
addEdge(adj, 3, 5);
minSizeVertexCover(adj, N);
|
Time Complexity : O(N)
Auxiliary space : O(N)
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
30 Apr, 2023
Like Article
Save Article