Introduction and Approximate Solution for Vertex Cover Problem
Last Updated :
22 Mar, 2023
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 the vertex cover. Although the name is Vertex Cover, the set covers all edges of the given graph. Given an undirected graph, the vertex cover problem is to find minimum size vertex cover.
The following are some examples.
Vertex Cover Problem is a known NP Complete problem, i.e., there is no polynomial-time solution for this unless P = NP. There are approximate polynomial-time algorithms to solve the problem though. Following is a simple approximate algorithm adapted from CLRS book.
Naive Approach:
Consider all the subset of vertices one by one and find out whether it covers all edges of the graph. For eg. in a graph consisting only 3 vertices the set consisting of the combination of vertices are:{0,1,2,{0,1},{0,2},{1,2},{0,1,2}} . Using each element of this set check whether these vertices cover all the edges of the graph. Hence update the optimal answer. And hence print the subset having minimum number of vertices which also covers all the edges of the graph.
Approximate Algorithm for Vertex Cover:
1) Initialize the result as {}
2) Consider a set of all edges in given graph. Let the set be E.
3) Do following while E is not empty
...a) Pick an arbitrary edge (u, v) from set E and add 'u' and 'v' to result
...b) Remove all edges from E which are either incident on u or v.
4) Return result
Below diagram to show the execution of the above approximate algorithm:
How well the above algorithm perform?
It can be proved that the above approximate algorithm never finds a vertex cover whose size is more than twice the size of the minimum possible vertex cover (Refer this for proof)
Implementation:
The following are C++ and Java implementations of the above approximate algorithm.
C++
#include<iostream>
#include <list>
using namespace std;
class Graph
{
int V;
list< int > *adj;
public :
Graph( int V);
void addEdge( int v, int w);
void printVertexCover();
};
Graph::Graph( int V)
{
this ->V = V;
adj = new list< int >[V];
}
void Graph::addEdge( int v, int w)
{
adj[v].push_back(w);
adj[w].push_back(v);
}
void Graph::printVertexCover()
{
bool visited[V];
for ( int i=0; i<V; i++)
visited[i] = false ;
list< int >::iterator i;
for ( int u=0; u<V; u++)
{
if (visited[u] == false )
{
for (i= adj[u].begin(); i != adj[u].end(); ++i)
{
int v = *i;
if (visited[v] == false )
{
visited[v] = true ;
visited[u] = true ;
break ;
}
}
}
}
for ( int i=0; i<V; i++)
if (visited[i])
cout << i << " " ;
}
int main()
{
Graph g(7);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(3, 4);
g.addEdge(4, 5);
g.addEdge(5, 6);
g.printVertexCover();
return 0;
}
|
Java
import java.io.*;
import java.util.*;
import java.util.LinkedList;
class Graph
{
private int V;
private LinkedList<Integer> adj[];
Graph( int v)
{
V = v;
adj = new LinkedList[v];
for ( int i= 0 ; i<v; ++i)
adj[i] = new LinkedList();
}
void addEdge( int v, int w)
{
adj[v].add(w);
adj[w].add(v);
}
void printVertexCover()
{
boolean visited[] = new boolean [V];
for ( int i= 0 ; i<V; i++)
visited[i] = false ;
Iterator<Integer> i;
for ( int u= 0 ; u<V; u++)
{
if (visited[u] == false )
{
i = adj[u].iterator();
while (i.hasNext())
{
int v = i.next();
if (visited[v] == false )
{
visited[v] = true ;
visited[u] = true ;
break ;
}
}
}
}
for ( int j= 0 ; j<V; j++)
if (visited[j])
System.out.print(j+ " " );
}
public static void main(String args[])
{
Graph g = new Graph( 7 );
g.addEdge( 0 , 1 );
g.addEdge( 0 , 2 );
g.addEdge( 1 , 3 );
g.addEdge( 3 , 4 );
g.addEdge( 4 , 5 );
g.addEdge( 5 , 6 );
g.printVertexCover();
}
}
|
Python3
from collections import defaultdict
class Graph:
def __init__( self , vertices):
self .V = vertices
self .graph = defaultdict( list )
def addEdge( self , u, v):
self .graph[u].append(v)
def printVertexCover( self ):
visited = [ False ] * ( self .V)
for u in range ( self .V):
if not visited[u]:
for v in self .graph[u]:
if not visited[v]:
visited[v] = True
visited[u] = True
break
for j in range ( self .V):
if visited[j]:
print (j, end = ' ' )
print ()
g = Graph( 7 )
g.addEdge( 0 , 1 )
g.addEdge( 0 , 2 )
g.addEdge( 1 , 3 )
g.addEdge( 3 , 4 )
g.addEdge( 4 , 5 )
g.addEdge( 5 , 6 )
g.printVertexCover()
|
C#
using System;
using System.Collections.Generic;
class Graph{
public int V;
public List< int > []adj;
public Graph( int v)
{
V = v;
adj = new List< int >[v];
for ( int i = 0; i < v; ++i)
adj[i] = new List< int >();
}
void addEdge( int v, int w)
{
adj[v].Add(w);
adj[w].Add(v);
}
void printVertexCover()
{
bool []visited = new bool [V];
for ( int u = 0; u < V; u++)
{
if (visited[u] == false )
{
foreach ( int i in adj[u])
{
int v = i;
if (visited[v] == false )
{
visited[v] = true ;
visited[u] = true ;
break ;
}
}
}
}
for ( int j = 0; j < V; j++)
if (visited[j])
Console.Write(j + " " );
}
public static void Main(String []args)
{
Graph g = new Graph(7);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(3, 4);
g.addEdge(4, 5);
g.addEdge(5, 6);
g.printVertexCover();
}
}
|
Javascript
<script>
class Graph
{
constructor(v)
{
this .V=v;
this .adj = new Array(v);
for (let i = 0; i < v; ++i)
this .adj[i] = [];
}
addEdge(v, w)
{
this .adj[v].push(w);
this .adj[w].push(v);
}
printVertexCover()
{
let visited = new Array( this .V);
for (let i = 0; i < this .V; i++)
visited[i] = false ;
for (let u = 0; u < this .V; u++)
{
if (visited[u] == false )
{
for (let i = 0; i < this .adj[u].length; i++)
{
let v = this .adj[u][i];
if (visited[v] == false )
{
visited[v] = true ;
visited[u] = true ;
break ;
}
}
}
}
for (let j = 0; j < this .V; j++)
if (visited[j])
document.write(j+ " " );
}
}
let g = new Graph(7);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 3);
g.addEdge(3, 4);
g.addEdge(4, 5);
g.addEdge(5, 6);
g.printVertexCover();
</script>
|
Output:
0 1 3 4 5 6
The Time Complexity of the above algorithm is O(V + E).
The space complexity of this solution is O(V), where V is the number of vertices of the graph. This is because we are using an array of size V to store the visited vertices.
Exact Algorithms:
Although the problem is NP complete, it can be solved in polynomial time for the following types of graphs.
1) Bipartite Graph
2) Tree Graph
The problem to check whether there is a vertex cover of size smaller than or equal to a given number k can also be solved in polynomial time if k is bounded by O(LogV) (Refer this)
We will soon be discussing exact algorithms for vertex cover.
Please Login to comment...