Implementation of Graph Coloring Algorithm in Java

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

  1. Adjacency matrix: adjacencyMatrix[u][v] = 1 means an edge exists between vertices u and v. The matrix is symmetric for an undirected graph.
  2. mColoring(currentVertex) is the backtracking engine. It calls nextColor() to get a valid colour for currentVertex. If successful and all vertices are coloured, it prints the solution. Otherwise, it recurses to the next vertex.
  3. nextColor(vertex) increments the colour of vertex cyclically (1 to numColors, 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.
  4. Backtracking: when colorAssignment[vertex] == 0 after nextColor(), the do-while loop in mColoring() breaks, returning execution to the previous recursive call, which then calls nextColor() again to try the next colour for its vertex.
  5. 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

  1. The graph is a 4-cycle: 1–2, 1–3, 2–4, 3–4. No two adjacent vertices can share a colour.
  2. Each row is one valid 3-colouring. For example, 1 2 3 2 means: vertex 1 → colour 1, vertex 2 → colour 2, vertex 3 → colour 3, vertex 4 → colour 2.
  3. The algorithm explores all possibilities with backtracking and prints every valid assignment, not just the first one.
  4. 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

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.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.