PrepStack · Markdown HTML

Constraint-satisfaction backtracking

Backtracking and constraint search · HTML

Formal shape

dfs(partial_assignment): emit when complete; choose unassigned variable x, try each v in domain(x) consistent with current constraints, apply x=v, propagate/recurse, and undo.

Recognition signals

False friends

SignalWhy it is different
Connectivity or shortest pathsWhen states can be reused by node, BFS or Dijkstra avoids enumerating complete histories.
A constraint graph with DP structureChains, trees, or low treewidth may admit DP that reuses equivalent partial assignments.
A matching or 2-SAT special caseA dedicated polynomial algorithm is stronger than generic exponential search.

Core invariant

At recursion entry, the partial assignment satisfies every activated constraint and every auxiliary set/count exactly matches it; a pruned branch has no legal completion.

State, transition, and processing order

ItemDefinition
StatePartial assignment, unassigned variables, incremental summaries for each constraint class, and optional reduced domains.
TransitionChoose a variable, try a compatible value, atomically update assignment and constraint state, recurse, then restore every change.
Frontier / orderOne consistent partial assignment in the search tree; selecting the variable with fewest candidates tends to fail earlier.

Python skeleton

def color_graph(graph, color_count):
    n = len(graph)
    color = [-1] * n
    def dfs(done):
        if done == n: return True
        candidates = [u for u in range(n) if color[u] < 0]
        u = max(candidates, key=lambda x: sum(color[v] >= 0 for v in graph[x]))
        forbidden = {color[v] for v in graph[u] if color[v] >= 0}
        for c in range(color_count):
            if c in forbidden: continue
            color[u] = c
            if dfs(done + 1): return True
            color[u] = -1
        return False
    return color if dfs(0) else None

Correctness sketch

  1. The invariant makes every attempted partial assignment legal.
  2. All currently legal values of the chosen variable are tried; any complete solution assigns one of them, so none is missed.
  3. Failure is returned only for an immediate contradiction or failed exhaustive children; undo restores the parent, making witnesses valid and failure conclusions sound.

Complexity

TimeSpaceParameters
Worst case O(d^n·check); pruning changes practice, not the exponential boundO(n+constraint_state)n is variable count and d the largest domain.

Edge cases

Error patterns

PatternWhy it fails / fix
Checking constraints only at leavesThis preserves doomed prefixes; validate or propagate immediately after apply.
Incomplete rollbackUndoing the assignment but not sets or counts contaminates sibling branches; pair all mutations.
Heuristic pruning without proofEvery prune must establish that no completion exists or it can remove valid answers.
Always choosing input orderCorrect but often slow; MRV or most-constrained-first exposes contradictions earlier.

Selection and exclusion rules

RelationTemplateBoundary
compositionTrie prefix searchString-path search can prune many candidates by shared prefixes.

Original micro-example

PartDetail
ResultSearch proves impossibility without waiting to inspect all 2³ complete assignments.
SetupColor the three vertices of a triangle with two colors so adjacent vertices differ.
TraceThe first two vertices are forced to differ; either color for the third conflicts with a neighbor, so the branch fails immediately.

Recall prompts

My notes