Graph Coloring is the problem of assigning colours to the vertices of an undirected graph such that no two adjacent vertices (vertices connected by an edge) share the same colour. The minimum number of colours needed is called the chromatic number of the graph. Graph colouring has real-world applications in scheduling, register allocation, and map colouring. This post implements the m-colouring backtracking algorithm, which finds all valid colourings of a graph using at most m colours.
Graph Coloring (m-Coloring Backtracking) in Java
import java.io.*;
class GraphColoring {
int[][] adjacencyMatrix; // adjacencyMatrix[i][j] = 1 if edge exists between i and j
int numVertices; // total number of vertices in the graph
int numEdges; // total number of edges
int numColors; // maximum number of colours allowed (m)
int[] colorAssignment; // colorAssignment[v] = colour assigned to vertex v
/** Reads the graph from user input */
void readGraph() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the number of vertices:");
numVertices = Integer.parseInt(reader.readLine());
adjacencyMatrix = new int[numVertices + 1][numVertices + 1];
colorAssignment = new int[numVertices + 1];
System.out.println("Enter the number of edges:");
numEdges = Integer.parseInt(reader.readLine());
// Initialise all edges to 0 (no connection)
for (int i = 1; i <= numVertices; i++)
for (int j = 1; j <= numVertices; j++)
adjacencyMatrix[i][j] = 0;
// Read each edge and mark it in the adjacency matrix (undirected)
for (int i = 1; i <= numEdges; i++) {
System.out.println("Enter edge " + i + " (vertex u then vertex v):");
int vertexU = Integer.parseInt(reader.readLine());
int vertexV = Integer.parseInt(reader.readLine());
adjacencyMatrix[vertexU][vertexV] = 1;
adjacencyMatrix[vertexV][vertexU] = 1; // undirected graph
}
System.out.println("Enter the number of colours (m):");
numColors = Integer.parseInt(reader.readLine());
}
/**
* Recursively assigns colours to vertices using backtracking.
* Prints each valid complete colouring found.
*
* @param currentVertex the vertex currently being coloured (1-indexed)
*/
void mColoring(int currentVertex) {
do {
// Try the next available colour for currentVertex
nextColor(currentVertex);
if (colorAssignment[currentVertex] == 0) {
// No valid colour exists for this vertex -- backtrack
break;
}
if (currentVertex == numVertices) {
// All vertices coloured -- print this valid solution
for (int i = 1; i <= numVertices; i++) {
System.out.print(colorAssignment[i] + " ");
}
System.out.println();
} else {
// Move to the next vertex
mColoring(currentVertex + 1);
}
} while (true);
}
/**
* Finds the next valid colour for the given vertex by incrementing
* its current colour and checking for conflicts with adjacent vertices.
* Sets colorAssignment[vertex] to 0 if no valid colour is found.
*
* @param vertex the vertex whose colour is being determined
*/
void nextColor(int vertex) {
do {
// Increment to the next candidate colour
colorAssignment[vertex] = (colorAssignment[vertex] + 1) % (numColors + 1);
if (colorAssignment[vertex] == 0) {
// Exhausted all colours -- signal backtrack
break;
}
// Check if any adjacent vertex already uses this colour
boolean conflictFound = false;
for (int neighbour = 1; neighbour <= numVertices; neighbour++) {
if (adjacencyMatrix[vertex][neighbour] != 0 &&
colorAssignment[neighbour] == colorAssignment[vertex]) {
conflictFound = true;
break;
}
}
if (!conflictFound) break; // found a valid colour
} while (true);
}
}
class GraphColoringMain {
public static void main(String[] args) throws IOException {
GraphColoring gc = new GraphColoring();
gc.readGraph();
gc.mColoring(1); // start colouring from vertex 1
}
}
How the Code Works
- Adjacency matrix:
adjacencyMatrix[u][v] = 1means an edge exists between verticesuandv. The matrix is symmetric for an undirected graph. mColoring(currentVertex)is the backtracking engine. It callsnextColor()to get a valid colour forcurrentVertex. If successful and all vertices are coloured, it prints the solution. Otherwise, it recurses to the next vertex.nextColor(vertex)increments the colour ofvertexcyclically (1 tonumColors, then wraps to 0). It then checks all neighbours in the adjacency matrix. If no neighbour has the same colour, the colour is valid. A result of 0 signals that all colours have been exhausted for this vertex, triggering backtracking.- Backtracking: when
colorAssignment[vertex] == 0afternextColor(), the do-while loop inmColoring()breaks, returning execution to the previous recursive call, which then callsnextColor()again to try the next colour for its vertex. - Output: every complete valid colouring is printed as a space-separated sequence of colour numbers (one per vertex).
Sample Output
Enter the number of vertices:
4
Enter the number of edges:
4
Enter edge 1 (vertex u then vertex v): 1, 2
Enter edge 2 (vertex u then vertex v): 1, 3
Enter edge 3 (vertex u then vertex v): 2, 4
Enter edge 4 (vertex u then vertex v): 3, 4
Enter the number of colours (m):
3
1 2 3 2
1 3 2 3
2 1 3 1
2 3 1 3
3 1 2 1
3 2 1 2
Output Explanation
- The graph is a 4-cycle: 1–2, 1–3, 2–4, 3–4. No two adjacent vertices can share a colour.
- Each row is one valid 3-colouring. For example,
1 2 3 2means: vertex 1 → colour 1, vertex 2 → colour 2, vertex 3 → colour 3, vertex 4 → colour 2. - The algorithm explores all possibilities with backtracking and prints every valid assignment, not just the first one.
- A 4-cycle can actually be 2-coloured (it is bipartite). Using m=2 would yield only those 2-colour solutions; m=3 finds all solutions with up to 3 colours.
See Also
- N-Queen Problem in Java
- Minimum Spanning Tree using Prim’s Algorithm in Java
- Implementing 0-1 Knapsack in Java
- Implementing Merge Sort Algorithm in Java
- Java Program for Longest Common Subsequence (LCS)
Conclusion
The m-colouring backtracking algorithm is a powerful exhaustive-search technique that finds all valid graph colourings by systematically assigning and retracting colour choices. While it can be exponential in the worst case, it is a clear illustration of the backtracking paradigm. In practice, graph colouring is NP-complete for general graphs, but polynomial-time algorithms exist for special graph families like trees and bipartite graphs.