Build a solution incrementally; abandon a partial solution (“backtrack”) as soon as it cannot be completed.

The skeleton

void solve(State& s, int depth) {
    if (complete(s)) { record(s); return; }
    if (!feasible(s)) return;                          // PRUNE
    for (Choice c : candidates(s)) {
        apply(s, c);
        solve(s, depth + 1);
        undo(s, c);                                    // the "backtrack"
    }
}

The undo is what makes it backtracking rather than brute force: state is mutated in place and restored, so no copying is needed.

Pruning — where all the performance is

Without pruning, backtracking is just exponential enumeration. The techniques, in rough order of value:

TechniqueIdea
Constraint propagationafter each choice, eliminate now-impossible options
Most-constrained variable first (MRV)branch on the variable with the fewest remaining options
Least-constraining valuetry the value that eliminates the fewest options for others
Boundingif the best possible completion is worse than the incumbent, prune
Symmetry breakingfix a canonical order among interchangeable choices
Forward checkingdetect a variable with zero remaining options immediately
Memoizationcache equivalent states
Early failure detectioncheck global feasibility (counts, parity, connectivity)

MRV is the single highest-value heuristic. Branching on the most constrained variable makes the tree narrow at the top, where it matters most. It is what turns a Sudoku solver from seconds to microseconds.

Symmetry breaking

If items are interchangeable, fix a canonical order so each solution is generated once:

// assigning items to groups: item i may only open group g if all groups < g are used
for (int g = 0; g <= usedGroups && g < maxGroups; g++) { ... }

Without this, a partition into groups is produced times. This is often a 10-100× speedup and is the first thing to add.

Other common symmetries: reflections and rotations of a board, permutations of identical pieces, and the choice of which element goes “first”.

Classic backtracking problems

ProblemKey pruning
N-Queenscolumn/diagonal bitmasks; place row by row
SudokuMRV + constraint propagation, or DLX
Graph colouringorder vertices by degree; symmetry-break the colours
Knight’s tourWarnsdorff’s rule (fewest onward moves first)
Subset sum / partitionsort descending; skip duplicates; bound the remaining sum
Hamiltonian pathprune on degree-0 or two degree-1 vertices remaining
Exact cover (pentominoes)Dancing Links
Crossword / word placementMRV on the most constrained slot
Maximum cliqueBron-Kerbosch with a colouring bound

N-Queens with bitmasks

void queens(int row, int cols, int d1, int d2, int n, int& count) {
    if (row == n) { count++; return; }
    int avail = ~(cols | d1 | d2) & ((1 << n) - 1);
    while (avail) {
        int bit = avail & -avail;
        avail ^= bit;
        queens(row + 1, cols | bit, (d1 | bit) << 1, (d2 | bit) >> 1, n, count);
    }
}

Three integers encode all the constraints, and the shifts propagate the diagonals automatically. in well under a second.

Warnsdorff’s rule

For a knight’s tour, always move to the square with the fewest onward moves. This heuristic finds a tour on boards up to almost without backtracking — a striking demonstration that a good ordering can dominate everything else.

Skipping duplicates

When the candidate list contains equal values, generate each distinct choice once:

sort(a.begin(), a.end());
for (int i = 0; i < n; i++) {
    if (i > 0 && a[i] == a[i-1] && !used[i-1]) continue;    // skip duplicates
    ...
}

The !used[i-1] condition forces equal elements to be used in index order. This is the standard idiom for “permutations with duplicates” and “subsets with duplicates”.

Backtracking vs the alternatives

SituationMethod
Small , need all solutionsbacktracking
Small , need one solutionbacktracking with early exit
Optimising, with a good boundbranch and bound
Overlapping subproblemsmemoization / DP
, subset structurebitmask DP
, splittablemeet in the middle
Exact cover structureDancing Links
Boolean constraintsa SAT solver, or 2-SAT if binary clauses
Too big for exactheuristics

See also: Branch and Bound · Dancing Links · Exact Cover