Here is a simple direct encoding:
For every node, introduce k variables (k = number of colors), and a clause that simply lists those variables (forcing at least one color to be chosen).
For every edge (X, Y) and color c, introduce a binary clause that prevents X and Y from both having color c at the same time, ie -Xc -Yc
.
For this graph, the total CNF in DIMACS format could look like this:
p cnf 9 12
1 2 3 0
4 5 6 0
7 8 9 0
-1 -4 0
-2 -5 0
-3 -6 0
-4 -7 0
-5 -8 0
-6 -9 0
-1 -7 0
-2 -8 0
-3 -9 0
A solver might give (for example, and obviously there are more possibilities) 1 -2 -3 -4 -5 6 -7 8 -9 0
meaning that node 0 got color 1, node 1 got color 3, and node 2 got color 2.
By the way note that the constraint "each node must have at most one color" was not used. Trivial post-processing can deal with that. For some graphs and some numbers of colors you may get a result where a node is assigned multiple colors (only if it does not share any of those colors with a neighbour, and usually if it's possible it still won't happen because the solver has no incentive to do it), you can simply pick any of them. If that's not acceptable, add a binary clause for every pair of variables associated with a node to ban them from being both set, eg -1 -2 0
, -1 -3 0
and so on.
There are more advanced encodings that scale better to larger graphs.