Computing Library › Classical Algorithms
Classical Algorithms

Backtracking

Backtracking builds candidate solutions incrementally and abandons a partial candidate as soon as it cannot be completed.

Try, and undo

Backtracking is a refined brute force. It builds a solution one choice at a time and, whenever the current partial solution cannot possibly be extended to a valid full solution, it undoes the last choice and tries another. This early abandonment, called pruning, is what separates backtracking from exhaustively enumerating every candidate.

The search tree

Kronos motion — classical

Conceptually, backtracking explores a tree of partial solutions with a depth-first search. Each node is a partial assignment, and children extend it by one more choice. Pruning cuts off entire subtrees whose root already violates a constraint, so the effective search can be far smaller than the full tree.

python
def solve_nqueens(n):
    cols, d1, d2, sols = set(), set(), set(), []
    def place(r, cur):
        if r == n:
            sols.append(cur[:]); return
        for c in range(n):
            if c in cols or (r-c) in d1 or (r+c) in d2:
                continue
            cols.add(c); d1.add(r-c); d2.add(r+c); cur.append(c)
            place(r+1, cur)
            cols.remove(c); d1.remove(r-c); d2.remove(r+c); cur.pop()
    place(0, [])
    return sols

Pruning is everything

Without pruning, backtracking degrades into checking every candidate, which is exponential. The techniques that make it practical are constraint propagation, which narrows future choices after each decision; the most-constrained-variable heuristic, which assigns the tightest variable first to fail fast; and bounding, which abandons a branch once a partial cost proves it cannot beat the best solution found so far, the idea behind branch and bound.

Where it is used

Backtracking solves constraint problems like the N-queens puzzle, Sudoku, graph colouring, and the boolean satisfiability problem. It is also the engine behind generating permutations and combinations and behind regular-expression matching. Its worst case can be exponential, so good pruning, constraint ordering, and choosing the most constrained variable first are what make it practical on real inputs.