Two classical chessboard puzzles that are also the standard first examples of backtracking and heuristic search.

N queens

Place queens so that none attack each other. Count solutions with bitmask backtracking: rows are placed in order, and three masks hold the attacked columns and diagonals for the current row.

long long nQueens(int n) {                         // number of solutions, bitmask backtracking
    long long cnt = 0; int full = (1 << n) - 1;
    auto rec = [&](auto self, int cols, int d1, int d2) -> void {
        if (cols == full) { cnt++; return; }
        for (int free = full & ~(cols | d1 | d2); free; free &= free - 1) {
            int b = free & -free;
            self(self, cols | b, (d1 | b) << 1 & full, (d2 | b) >> 1);
        }
    };
    rec(rec, 0, 0, 0);
    return cnt;
}
123456789101112
solutions10021044092352724268014200

A single solution for any can be written down directly (explicit constructions by residue of mod 6), so “find one” is while “count all” is exponential.

Knight’s tour

Visit every square exactly once with knight moves. Warnsdorff’s rule: always move to the square with the fewest onward moves. It finds tours on almost every board in ; with a bad tie-break it can get stuck, so the code retries with random tie-breaking.

vector<pair<int, int>> knightsTourOnce(int n, int sr, int sc, mt19937* rng) {   // Warnsdorff; ties: farther from centre, or random
    int dr[] = {2, 1, -1, -2, -2, -1, 1, 2}, dc[] = {1, 2, 2, 1, -1, -2, -2, -1};
    vector<vector<int>> seen(n, vector<int>(n, 0)); vector<pair<int, int>> path{{sr, sc}}; seen[sr][sc] = 1;
    auto deg = [&](int r, int c) { int d = 0; for (int k = 0; k < 8; k++) { int x = r + dr[k], y = c + dc[k]; d += x >= 0 && x < n && y >= 0 && y < n && !seen[x][y]; } return d; };
    for (int step = 1; step < n * n; step++) {
        auto [r, c] = path.back(); int br = -1, bc = -1, bd = 9; double bdist = -1;
        for (int k = 0; k < 8; k++) {
            int x = r + dr[k], y = c + dc[k];
            if (x < 0 || x >= n || y < 0 || y >= n || seen[x][y]) continue;
            int d = deg(x, y); double dist = (x - (n - 1) / 2.0) * (x - (n - 1) / 2.0) + (y - (n - 1) / 2.0) * (y - (n - 1) / 2.0);
            if (rng) dist = (*rng)() % 1000;
            if (d < bd || (d == bd && dist > bdist)) bd = d, bdist = dist, br = x, bc = y;
        }
        if (br < 0) return {};
        seen[br][bc] = 1; path.push_back({br, bc});
    }
    return path;
}
vector<pair<int, int>> knightsTour(int n, int sr = 0, int sc = 0) {   // empty if none found (n = 2, 3, 4 have none)
    auto t = knightsTourOnce(n, sr, sc, nullptr);
    mt19937 rng(12345);
    for (int it = 0; it < 200 && t.empty(); it++) t = knightsTourOnce(n, sr, sc, &rng);
    return t;
}
FactValue
open tours exist and
closed tours exist ()even (Schwenk’s theorem gives all boards)
exact searchbacktracking with Warnsdorff ordering, or a Hamiltonian-path DP on tiny boards