Problem. Fill an grid (, classic ) with digits so that every row, column and box contains each digit once, extending the given clues.

ViewFormulationUse
backtracking with bitmasksper row / column / box a mask of used digits; candidates = complement of the unionfastest simple solver
constraint propagationnaked single: a cell with one candidate; hidden single: a digit with one possible cell in a unitwhat MRV does implicitly; humans solve with it
exact cover rows (cell, digit), columns: cell filled, row has digit, column has digit, box has digitDancing Links, see Exact Cover and Dancing Links
graph colouringthe Sudoku graph ( vertices, each adjacent to others: 20 for )proper -colouring extending a precolouring
complexity Sudoku completion is NP-complete (Yato and Seta, 2003)no polynomial algorithm expected
CountValue
completed grids (Shidoku)288
completed grids (Felgenhauer and Jarvis, 2005)
essentially different grids (up to symmetry and relabelling) (Russell and Jarvis, 2006)
minimum clues for a unique solution17 (McGuire, Tugemann and Civario 2012, exhaustive computer search)
// N x N Sudoku, N = B * B; g[r][c] = 0 for empty, else 1..N. Counts solutions up to `limit`
// (limit = 1: solve, limit = 2: uniqueness check); the first solution found is stored in sol.
struct Sudoku {
    int B, N, full; vector<vector<int>> g, sol; vector<int> row, col, box; ll found = 0, limit = 1; bool ok = true;
    Sudoku(int B, const vector<vector<int>>& g0) : B(B), N(B * B), full((1 << B * B) - 1), g(g0), row(N), col(N), box(N) {
        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) if (int d = g[r][c]) {
            int bit = 1 << (d - 1), b = r / B * B + c / B;
            if ((row[r] | col[c] | box[b]) & bit) ok = false;   // contradictory clues
            row[r] |= bit; col[c] |= bit; box[b] |= bit;
        }
    }
    void dfs() {
        int br = -1, bc = -1, best = N + 1, cand = 0;
        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) if (!g[r][c]) {   // minimum remaining values
            int m = full & ~(row[r] | col[c] | box[r / B * B + c / B]), k = __builtin_popcount(m);
            if (k < best) { best = k, br = r, bc = c, cand = m; if (k == 0) return; }
        }
        if (br < 0) { if (found++ == 0) sol = g; return; }
        int b = br / B * B + bc / B;
        for (int m = cand; m && found < limit; m &= m - 1) {
            int bit = m & -m;
            g[br][bc] = __builtin_ctz(bit) + 1; row[br] ^= bit; col[bc] ^= bit; box[b] ^= bit;
            dfs();
            g[br][bc] = 0; row[br] ^= bit; col[bc] ^= bit; box[b] ^= bit;
        }
    }
    ll count(ll lim) { limit = lim; found = 0; if (ok) dfs(); return found; }
};