Independent sets are set of vertices or edges in which the pair of any two vertices or edges are not adjacent to each other. Assuming that Independent sets mean Independent sets of vertices, we have to find a set of such vertices in which any two pairs of the vertex are not adjacent to each other.
Using graph coloring we can solve this problem. We will modify the graph coloring method as instead of using different colors we will only use two colors i.e 0,1. So we will assume that those vertices which are labeled 0 are a part of the set and others are not. So the vertices labeled with 0 doesn’t have any adjacent vertex labeled with 0.
The basic idea about the functioning of the call by references in java and concepts of vector is a must. Also, we are assuming the index labeled as the vertex name and the value in the vector at that index as the color of that vertex (either 0 or 1). The initially found variable is set to false i.e no set of the desired size is found. We will be making use of the word removed and the color ‘0’ for any vertex. Both indicate the same thing that the particular vertex can be removed from the graph and can be included in the set.
Approach:
- The input of the program is an adjacent matrix of the graph and the max size of the set is given here. First we have to make the adjacency list of the graph matrix. Now we will be running a loop for each vertex, by first giving the ith vertex color ‘0’ and then finding all other possible vertices which can be given color ‘0’(included in the set).
- So we are making a vector named ‘color’ and initialize the vector with the color of all index (vertices) as ‘1’ and the ith vertex as ‘0’. Then we will be checking for all the possible vertices that can be given the color ‘0’ (included in the set) using a Util() method, described below.
- Util() method: This method calls other two method named can_remove() and remove_all(). The main aim of this method is to remove all those vertices which can be removed from the color vector if the ‘ith’ vertex is removed(assigned ‘0’). This method finds the index of the vertex that can be removed using the above two methods. Then it assigns ‘0’ to that vertex, and it continues doing this till there is no more vertex left to be removed. It returns the modified color vector.
- can_remove() method checks for whether the given vertex can be assigned ‘0’ without any difficulty. It compares each neighbor vertex for the given vertex and checks whether there is any neighbor with ‘0’ or not. If no vertex is there with such a case then this vertex is assigned a value ‘0’. It returns a boolean value indicating yes or no.
- remove_all() method is used to find the vertex whose removal will give a large number of vertices to be removed each time. This step is mainly a greedy approach. It finds the number of vertices that can be removed after the removal of a particular vertex and finds the max value of all those numbers and returns the index of that particular vertex whose removal will result in the removal of maximum vertices. Then this vertex is removed in Util() method.
- So till now we have understood what Util(), remove_all() and can_remove() method are doing. Basically for each ith color vector with ‘ith’ vertex being ‘0’, these methods tries to find the number of vertices that can be removed from the graph (assigned ‘0’). So after calling this Util() method the color vector is being modified and the number of vertices that can be assigned ‘0’ is given that value.
- Now since the color vector is modified, so we have to count the number of vertices that are assigned’0′ (which means the vertices which can be included in the set). If the count is larger than the desired size then we have found the solution and found variable is set to true and output is done and loops break else it continues trying next color vector with the next vertex being removed. The count is done by the Util3() method.
But we are forgetting one case as shown in the following image :
Here instead of coloring the second colored vertex in the first diagram, we will color one of its adjacent vertex as shown in the second fig. In doing so we will get many vertices in the set. Hence, for each color vector, we will call Util2() method. This case can arise only when there is a certain vertex which is having the value ‘1’ (uncolored) and having only one colored adjacent vertex as shown above.
- Util2() method basically checks for each vertex that is not removed (having ‘1’), whether that vertex is having only one adjacent vertex colored (value ‘1’). If found any such vertex then this method will swap the color among the vertices and recall the Util() method to refresh the color vector. This can be proved easily that this method will always either increase the number of a vertex with ‘0’ or the number will remain the same. It will never decrease the count of colored vertices. So this approach proves extra beneficial for our approach.
Why always increase?
There is only swap of color between two adjacent vertices. Hence, the count will remain same till now. Thinking for rest of the configuration we can say that before swap the newly colored vertex is not having more than one colored adjacent vertex. So, after swap also there are no adjacent vertices to it that are colored. This will maintain the property of independent sets.
- Till now if we have any solution then we will set found true otherwise will save the configuration of color vector for further use. All this is done for each ‘ith’ vertex in the loop and the modified color vector is stored in the vector of vectors named set_found in the program.
- If the desired size is not found till now, then we will try our last case that we will be performing pairwise intersection of all the generated sets of configurations.
In this, we will repeat the same procedure starting with the color vector again and maintaining the configurations generated. The only difference is that we will not begin by assigning ‘0’ to the ith vertex. Instead of that, we will check pairs of configuration (in the set_found) for those vertexes that are labeled with ‘0’ and are common to both sets. They will be labeled ‘0’ in the color vector and for the rest part the above procedure will be the same, to check the maximum size of set possible and the above case.
Implementation:
Java
// Java Program to Find Independent Sets // in a Graph using Graph Coloring import java.io.*; import java.util.*; // save file with the name "GFG2.java" public class GFG2 { // main class public static void main(String[] args) throws Exception { // inputting the graph and forming it's adjacency // list. System.out.println( "The number of vertices in the graph is taken as 4" ); int n = 4 ; Vector<Vector<Integer> > adjacency_matrix = new Vector<Vector<Integer> >(n, (n)); /* the input matrix is 0111 1011 1101 1110 */ for ( int i = 0 ; i < n; ++i) { Vector<Integer> adj = new Vector<Integer>(n); for ( int j = 0 ; j < n; ++j) if (i == j) adj.add( 0 ); else adj.add( 1 ); adjacency_matrix.add(adj); } Vector<Vector<Integer> > adjacency_list = new Vector<Vector<Integer> >(); for ( int i = 0 ; i < n; ++i) { Vector<Integer> adj_list = new Vector<Integer>(); for ( int j = 0 ; j < n; ++j) { if (adjacency_matrix.get(i).get(j) == 1 ) adj_list.add(j); } adjacency_list.add(adj_list); } // taking the minimum size of the set required. System.out.println( "The minimum size of the set required is taken as 2" ); // the least size of the set required int x = 2 ; // complement of the size int y = n - x; int found = 0 ; int size = 0 ; int min = n + 1 ; // making a set_found vector to store all the // possible sets . Vector<Vector<Integer> > set_found = new Vector<Vector<Integer> >(); System.out.println( "Searching for the set" ); for ( int i = 0 ; i < n; ++i) { // if set is found if (found == 1 ) break ; // a cover vector to have the state of all the // vertices initially. Vector<Integer> color = new Vector<Integer>(n); for ( int j = 0 ; j < n; ++j) color.add( 1 ); // starting by putting the ith node in set color.set(i, 0 ); // then finding all the nodes to be pushed in // the set by calling function Util(adjacency_list, color); // finding the number of those which cannot be // pushed in set size = Util3(color); if (size < min) min = size; // if the number of elements in set are more or // equal to the amount required. if (size <= y) { System.out.println( "Independent set of size " + (n - size) + "found" ); for ( int j = 0 ; j < n; ++j) if (color.get(j) == 0 ) System.out.print(j + 1 + " " ); System.out.println(); set_found.add(color); found = 1 ; break ; } // not sufficient nodes found // calling util2 function // main aim of calling this function 'x' times // is that for any undirected graph the maximum // number of edges with x nodes is x(x+1)/2; so // we are trying for each possible edge . for ( int j = 0 ; j < x; ++j) Util2(adjacency_list, color, j); // repeating same procedure as discussed above size = Util3(color); if (size < min) min = size; System.out.println( "Independent set of size " + (n - size) + "found" ); for ( int j = 0 ; j < n; ++j) if (color.get(j) == 0 ) System.out.print(j + 1 + " " ); System.out.println(); set_found.add(color); if (size <= y) { found = 1 ; break ; } } int r = set_found.size(); // searching pairwise. // repeating same procedure as above // this time taking those set which have common // vertices in them and again trying for uncommon // ones. for ( int a = 0 ; a < r; ++a) { if (found == 1 ) break ; for ( int b = a + 1 ; b < r; ++b) { if (found == 1 ) break ; Vector<Integer> color = new Vector<Integer>(n); for ( int j = 0 ; j < n; ++j) color.add( 1 ); for ( int c = 0 ; c < n; ++c) if (set_found.get(a).get(c) == 0 && set_found.get(b).get(c) == 0 ) color.set(c, 0 ); Util(adjacency_list, color); size = Util3(color); if (size < min) min = size; if (size <= y) { System.out.println( "Independent set of size" + (n - size)); for ( int j = 0 ; j < n; ++j) if (color.get(j) == 0 ) System.out.print(j + 1 + " " ); System.out.println(); found = 1 ; break ; } for ( int j = 0 ; j < y; ++j) Util2(adjacency_list, color, j); size = Util3(color); if (size < min) min = size; System.out.println( "Independent set of size " + (n - size) + "found" ); for ( int j = 0 ; j < n; ++j) if (color.get(j) == 0 ) System.out.print(j + 1 + " " ); System.out.println(); if (size <= y) { found = 1 ; break ; } } } // if found if (found == 1 ) System.out.println( "Found the set of given least possible size" ); else System.out.println( "Couldn't find the set of least size given" ); } // utility function to label maximum vertices with // 0,that can be included in the set. It takes the // maximum number of vertices which can be removed each // time. public static void Util(Vector<Vector<Integer> > adjacency_list, Vector<Integer> color) { int a = 0 ; while (a != - 1 ) { a = remove_all(adjacency_list, color); if (a != - 1 ) color.set(a, 0 ); } } // This method tries whether it is possible to // remove any adjacent vertex of any removed vertex if // yes then it will remove that and call Util again and // modify the set. public static void Util2(Vector<Vector<Integer> > adjacency_list, Vector<Integer> color, int j) { int cnt = 0 ; Vector<Integer> tmp_color = new Vector<Integer>(); for ( int g = 0 ; g < color.size(); ++g) tmp_color.add(color.get(g)); for ( int i = 0 ; i < color.size(); ++i) { if (tmp_color.get(i) == 1 ) { int sum = 0 ; int idx = - 1 ; for ( int g = 0 ; g < adjacency_list.get(i).size(); ++g) if (tmp_color.get(adjacency_list.get(i).get(g))== 0 ) { idx = g; sum++; } if (sum == 1 && color.get(adjacency_list.get(i).get(idx)) == 0 ) { tmp_color.set(adjacency_list.get(i).get(idx), 1 ); tmp_color.set(i, 0 ); Util(adjacency_list, tmp_color); ++cnt; } if (cnt > j) break ; } } for ( int g = 0 ; g < color.size(); ++g) color.set(g, tmp_color.get(g)); } // returning the number of vertices that can't be // included in the set. public static int Util3(Vector<Integer> color) { int cnt = 0 ; for ( int i = 0 ; i < color.size(); i++) if (color.get(i) == 1 ) ++cnt; return cnt; } // returns the index of the vertex whose removal will // give more vertex to be removed. This is basically a // greedy approach to get the maximum possible set size. public static int remove_all(Vector<Vector<Integer> > adjacency_list, Vector<Integer> color) { int a = - 1 , max = - 1 ; for ( int i = 0 ; i < color.size(); ++i) { if (color.get(i) == 1 && can_remove(adjacency_list.get(i), color) == 1 ) { Vector<Integer> tmp_color = new Vector<Integer>(); for ( int j = 0 ; j < color.size(); ++j) tmp_color.add(color.get(j)); tmp_color.set(i, 0 ); int sum = 0 ; for ( int j = 0 ; j < tmp_color.size(); ++j) if (tmp_color.get(j) == 1 && can_remove(adjacency_list.get(j), tmp_color)== 1 ) ++sum; if (sum > max) { max = sum; a = i; } } } return a; } // checking that a vertex can be removed or not public static int can_remove(Vector<Integer> adj_list, Vector<Integer> color) { int check = 1 ; for ( int i = 0 ; i < adj_list.size(); ++i) if (color.get(adj_list.get(i)) == 0 ) check = 0 ; return check; } } |
The number of vertices in the graph is taken as 4 The minimum size of the set required is taken as 2 Searching for the set Independent set of size 1found 1 Independent set of size 1found 2 Independent set of size 1found 2 Independent set of size 1found 2 Independent set of size 1found 1 Independent set of size 1found 1 Independent set of size 1found 1 Independent set of size 1found 2 Independent set of size 1found 2 Independent set of size 1found 2 Couldn't find the set of least size given
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!