Combinatorics

Graph Coloring

Color vertices so adjacent ones differ — minimum colors needed is the chromatic number

Graph coloring assigns colors to vertices of a graph such that no two adjacent vertices share a color. The minimum number of colors needed is the chromatic number χ(G). NP-hard in general, but bounded by maximum degree (χ ≤ Δ + 1), and famously, every planar graph is 4-colorable (proved 1976, first major theorem proved by computer). Foundational in combinatorial optimization, scheduling, register allocation in compilers, and frequency assignment.

  • Chromatic number χ(G)Min colors to color G so adjacent vertices differ
  • NP-hardComputing χ(G) is NP-hard in general
  • Brooks' theoremχ(G) ≤ Δ(G) (max degree), except complete graphs and odd cycles
  • Greedy boundχ(G) ≤ Δ(G) + 1 always, achievable by greedy
  • Four Color TheoremEvery planar graph is 4-colorable (Appel-Haken 1976)
  • Bipartite ⟺ 2-colorable ⟺ no odd cyclesEquivalent characterizations

Interactive visualization

Press play, or step through manually. The visualization is yours to drive — try it before reading on.

Open visualization fullscreen ↗

Watch the 60-second explainer

A condensed visual walkthrough — narrated, captioned, under a minute.

Definition

A proper k-coloring of a graph G assigns one of k colors to each vertex such that no two adjacent vertices share a color.

The chromatic number χ(G) is the smallest k for which a proper k-coloring exists.

Equivalent definition — partition vertices into k independent sets (sets with no edges within them). Each independent set gets one color.

Examples:

  • Empty graph (no edges) — χ = 1.
  • Bipartite graph — χ = 2.
  • Triangle K₃ — χ = 3.
  • Complete graph Kₙ — χ = n.
  • Cycle C₅ (pentagon) — χ = 3 (odd cycle).
  • Cycle C₆ (hexagon) — χ = 2 (even cycle, bipartite).

Standard bounds

BoundStatementNotes
Trivial lowerχ(G) ≥ ω(G)ω = clique number; cliques need distinct colors
Greedy upperχ(G) ≤ Δ(G) + 1Δ = max degree; achievable by greedy algorithm
Brooks (1941)χ(G) ≤ Δ(G), except Kₙ and odd cyclesTightens greedy bound for most graphs
Four Color Theoremχ(G) ≤ 4 if G planarAppel-Haken 1976, computer-assisted
Heawood (1890)χ(G) ≤ ⌊(7 + √(1 + 48g))/2⌋ on genus-g surfaceFor surface non-planar; tight for g ≥ 1
Vizing edge coloringχ'(G) ≤ Δ(G) + 1Edge coloring (chromatic index)

The Four Color Theorem

Every planar graph (graph drawable in the plane without crossings) can be properly colored with at most 4 colors.

History:

  • Conjectured 1852 by Francis Guthrie (color map of England's counties, noticed 4 always sufficed).
  • Heawood (1890) proved 5-color theorem with simpler argument.
  • Appel and Haken (1976) proved 4-color theorem using computer-aided case analysis — checking ~1936 reducible configurations.
  • Robertson, Sanders, Seymour, Thomas (1996) gave simpler computer-assisted proof.
  • Gonthier (2005) formally verified the proof in the Coq proof assistant.

The theorem says every map (with regions = countries, edges = adjacencies) can be colored using only 4 colors. Generalizations to higher-genus surfaces give different bounds (Heawood's formula).

Greedy coloring algorithm

Order vertices v₁, v₂, ..., vₙ. For each vertex in turn:

  1. Look at colors of already-colored neighbors.
  2. Assign vertex the smallest color not used by neighbors.

Since each vertex has at most Δ(G) neighbors, at most Δ(G) colors are blocked, so a color in {1, ..., Δ + 1} is always available. Therefore χ(G) ≤ Δ(G) + 1.

Greedy is fast (linear in size of graph) but not optimal. Different orderings give different colorings. Welsh-Powell algorithm orders by descending degree — often gives better results.

Bipartite — when 2 colors suffice

A graph is bipartite if its vertices can be partitioned into two independent sets — equivalently, if it's 2-colorable.

König's theorem — A graph is bipartite if and only if it has no odd cycles.

Algorithm — BFS from any vertex, alternate colors at each BFS level. If you ever try to color a vertex differently from how it's already colored, an odd cycle exists and the graph isn't bipartite.

Bipartite testing is in P (linear time). 3-coloring is already NP-hard.

Real-world applications

Register allocation in compilers

Variables in a program become vertices. Two variables are connected if their live ranges overlap (used at the same time). The graph's chromatic number = minimum CPU registers needed without spilling to memory.

Chaitin's register allocation algorithm — build interference graph, color with k = number of registers, "spill" vertices that can't be colored. Critical for compiler optimization.

Scheduling

Events become vertices. Conflicting events (same room, same person, etc.) are connected. Colors = time slots. Minimum number of slots = chromatic number.

Examples — exam scheduling, conference talks, employee shifts.

Frequency assignment

Radio/cell towers become vertices. Connect towers whose ranges overlap (would interfere). Colors = frequencies. Want fewest distinct frequencies. Same coloring problem.

Sudoku

Sudoku is graph coloring on an 81-vertex graph (one per cell), with edges between cells in the same row, column, or 3×3 box. Needs exactly 9 colors. Each Sudoku puzzle is a partial coloring; solving = completing it.

JavaScript — graph coloring

// Graph as adjacency list: { v: [neighbors] }

// Greedy coloring — simple ordering
function greedyColoring(graph) {
  const colors = {};
  const vertices = Object.keys(graph);
  for (const v of vertices) {
    const neighborColors = new Set(
      (graph[v] || []).map(n => colors[n]).filter(c => c !== undefined)
    );
    let c = 0;
    while (neighborColors.has(c)) c++;
    colors[v] = c;
  }
  return colors;
}

// Welsh-Powell: order by descending degree
function welshPowell(graph) {
  const sortedVertices = Object.keys(graph).sort(
    (a, b) => (graph[b]?.length || 0) - (graph[a]?.length || 0)
  );
  const colors = {};
  for (const v of sortedVertices) {
    const neighborColors = new Set(
      (graph[v] || []).map(n => colors[n]).filter(c => c !== undefined)
    );
    let c = 0;
    while (neighborColors.has(c)) c++;
    colors[v] = c;
  }
  return colors;
}

// Test: triangle K₃
const triangle = {
  A: ['B', 'C'],
  B: ['A', 'C'],
  C: ['A', 'B']
};
console.log(greedyColoring(triangle)); // {A: 0, B: 1, C: 2} (3 colors, as needed)

// Test: cycle C₆ (bipartite)
const c6 = {
  '0': ['1', '5'], '1': ['0', '2'], '2': ['1', '3'],
  '3': ['2', '4'], '4': ['3', '5'], '5': ['4', '0']
};
console.log(greedyColoring(c6));  // alternating 0, 1 (2 colors)

// Bipartite test via BFS
function isBipartite(graph) {
  const colors = {};
  const vertices = Object.keys(graph);
  for (const start of vertices) {
    if (colors[start] !== undefined) continue;
    const queue = [start];
    colors[start] = 0;
    while (queue.length) {
      const v = queue.shift();
      for (const n of (graph[v] || [])) {
        if (colors[n] === undefined) {
          colors[n] = 1 - colors[v];
          queue.push(n);
        } else if (colors[n] === colors[v]) {
          return false;  // adjacent same color = odd cycle
        }
      }
    }
  }
  return true;
}

console.log(isBipartite(c6));      // true (even cycle)
console.log(isBipartite(triangle)); // false (triangle = odd cycle)

Where graph coloring shows up

  • Compiler register allocation. Map program variables to CPU registers using interference graph coloring. Chaitin-Briggs algorithm, used in GCC, LLVM, others.
  • Scheduling problems. Exams, classes, conferences, employee shifts. NP-hard in general, but heuristics like Welsh-Powell work well.
  • Frequency assignment. Cell towers, WiFi channels, radio broadcasting. Adjacent regions need distinct frequencies.
  • Map coloring. Geographic maps colored so adjacent regions differ. Four Color Theorem says 4 always suffice.
  • Sudoku and puzzles. Sudoku is a 9-coloring problem. Other "constraint satisfaction" puzzles often reduce to coloring.
  • Theoretical CS. Coloring is canonical NP-hard problem; many problems reduce to (or from) coloring.
  • Bioinformatics. Sequence assembly, conflict graphs. Coloring assigns parts to non-overlapping experiments.

Common mistakes

  • Confusing chromatic number with maximum degree. χ ≤ Δ + 1, but often χ ≪ Δ + 1. A bipartite graph with Δ = 100 still has χ = 2.
  • Forgetting bipartite ↔ no odd cycles. Some try to 2-color a graph and fail because of an odd cycle they didn't notice. Always check via BFS/DFS.
  • Believing greedy is optimal. Greedy depends on vertex ordering; bad orderings give bad colorings. Welsh-Powell (descending degree) usually better but not optimal.
  • Mixing up vertex and edge coloring. Vertex coloring — adjacent vertices differ; chromatic number χ. Edge coloring — adjacent edges differ; chromatic index χ' ≤ Δ + 1 (Vizing). Different problems.
  • Trying to compute χ exactly for huge graphs. NP-hard. For practical large graphs, use heuristics (Welsh-Powell, DSATUR) or approximations.
  • Forgetting the four-color theorem requires planarity. Non-planar graphs can need many more colors; Kₙ requires n. Four-color is special to planar graphs.

Frequently asked questions

What's the formal definition?

A proper k-coloring of graph G assigns one of k colors to each vertex such that no edge connects two same-colored vertices. The chromatic number χ(G) is the smallest k for which a proper k-coloring exists. Equivalent — partition vertices into k independent sets (sets with no internal edges). Computing χ(G) exactly is NP-hard for general graphs.

Why is the Four Color Theorem famous?

Stated 1852 — every map (planar graph) can be colored with 4 colors so adjacent regions differ. Resisted proof for 124 years. Finally proved 1976 by Appel and Haken using extensive computer-assisted case analysis (~1936 reducible configurations checked). First major theorem proved by computer; sparked debate about the nature of mathematical proof. Simpler proof by Robertson, Sanders, Seymour, Thomas (1996) — still computer-assisted.

How do you 2-color a graph?

2-coloring is possible iff the graph is bipartite (no odd cycles). Algorithm — BFS/DFS from each connected component, alternating colors at each level. If you ever assign two colors to same vertex, the graph has an odd cycle and isn't bipartite. Polynomial-time algorithm for 2-coloring; 3-coloring jumps to NP-hard.

What's the chromatic number of a complete graph?

For Kₙ (complete graph on n vertices, every pair connected), χ(Kₙ) = n. Every vertex needs a distinct color. Complete graphs are the most "constrained" graphs; their chromatic number equals their order.

How does greedy coloring work?

Order vertices v₁, ..., vₙ. For each vertex in order, assign the smallest color not used by any already-colored neighbor. Always produces a proper coloring with at most Δ(G) + 1 colors (where Δ is max degree), because at each vertex you've used at most Δ colors among neighbors. Greedy ≤ Δ + 1 is tight (complete graphs). Often gives χ + 1 or χ + few in practice.

What does Brooks' theorem say?

For connected graph G that's not a complete graph and not an odd cycle, χ(G) ≤ Δ(G). Stronger than the greedy bound Δ + 1. Exceptions — complete graphs (need Δ + 1 = n colors) and odd cycles (need 3 colors with Δ = 2). So Brooks gives χ ≤ Δ except for these two special cases. Important refinement of the greedy bound.

Where does graph coloring show up in computer science?

Register allocation in compilers — variables are vertices, edges connect variables whose lifetimes overlap, colors are CPU registers. Want fewest registers (= chromatic number). Chaitin's algorithm uses graph coloring. Scheduling — events are vertices, edges connect conflicting events (same time, etc.), colors are time slots. Frequency assignment — radio towers as vertices, edges between nearby towers, colors as frequencies.