All Euler problems
Project Euler

Weak Queens

A weak queen on a chessboard attacks only the 8 adjacent squares (like a king). Let f(n) be the number of ways to place n non-attacking weak queens on an n x n board with exactly one queen per row....

Source sync Apr 19, 2026
Problem #0534
Level Level 27
Solved By 371
Languages C++, Python
Answer 11726115562784664
Length 315 words
dynamic_programminglinear_algebragraph

Problem Statement

This archive keeps the full statement, math, and original media on the page.

The classical eight queens puzzle is the well known problem of placing eight chess queens on an \(8 \times 8\) chessboard so that no two queens threaten each other. Allowing configurations to reappear in rotated or mirrored form, a total of \(92\) distinct configurations can be found for eight queens. The general case asks for the number of distinct ways of placing \(n\) queens on an \(n \times n\) board, e.g. you can find \(2\) distinct configurations for \(n=4\).

Let’s define a weak queen on an \(n \times n\) board to be a piece which can move any number of squares if moved horizontally, but a maximum of \(n - 1 - w\) squares if moved vertically or diagonally, \(0 \le w < n\) being the "weakness factor". For example, a weak queen on an \(n \times n\) board with a weakness factor of \(w=1\) located in the bottom row will not be able to threaten any square in the top row as the weak queen would need to move \(n - 1\) squares vertically or diagonally to get there, but may only move \(n - 2\) squares in these directions. In contrast, the weak queen is not handicapped horizontally, thus threatening every square in its own row, independently from its current position in that row.

Let \(Q(n,w)\) be the number of ways \(n\) weak queens with weakness factor \(w\) can be placed on an \(n \times n\) board so that no two queens threaten each other. It can be shown, for example, that \(Q(4,0)=2\), \(Q(4,2)=16\) and \(Q(4,3)=256\).

Let \(S(n)=\displaystyle \sum _{w=0}^{n-1} Q(n,w)\).

Let \(S(n)=\displaystyle \sum _{w=0}^{n-1} Q(n,w)\)

Find \(S(14)\).

Problem 534: Weak Queens

Mathematical Foundation

Theorem 1 (Reduction to Constrained Permutations). A placement of nn non-attacking weak queens, one per row, on an n×nn \times n board is valid if and only if the column assignment σSn\sigma \in S_n satisfies σ(i)σ(i+1)2|\sigma(i) - \sigma(i+1)| \ge 2 for all 1in11 \le i \le n - 1.

Proof. Since there is exactly one queen per row, the column assignments σ(1),,σ(n)\sigma(1), \ldots, \sigma(n) must be distinct, forming a permutation. A weak queen in row ii, column σ(i)\sigma(i) attacks the 8 cells at Chebyshev distance 1. Two queens in rows ii and jj can attack each other only if ij1|i - j| \le 1 and σ(i)σ(j)1|\sigma(i) - \sigma(j)| \le 1. Since queens are in distinct rows, the only potentially attacking pairs are in consecutive rows ii and i+1i+1, requiring σ(i)σ(i+1)1|\sigma(i) - \sigma(i+1)| \le 1. The non-attacking condition is therefore σ(i)σ(i+1)2|\sigma(i) - \sigma(i+1)| \ge 2 for all consecutive ii. \square

Theorem 2 (Bitmask DP Correctness). Define dp[mask][c]\mathrm{dp}[\mathrm{mask}][c] as the number of ways to fill mask|\mathrm{mask}| rows using column set mask\mathrm{mask}, with the last queen in column cmaskc \in \mathrm{mask}. Then

f(n)=c=0n1dp[2n1][c]f(n) = \sum_{c=0}^{n-1} \mathrm{dp}[2^n - 1][c]

where the recurrence is

dp[mask{c}][c]+=dp[mask][c]for all cmask,  cc2.\mathrm{dp}[\mathrm{mask} \cup \{c\}][c] \mathrel{+}= \mathrm{dp}[\mathrm{mask}][c'] \quad \text{for all } c \notin \mathrm{mask},\; |c - c'| \ge 2.

Proof. The DP state captures exactly the information needed: which columns have been used (the bitmask ensures the permutation property) and which column was most recently placed (needed to enforce the σ(i)σ(i+1)2|\sigma(i) - \sigma(i+1)| \ge 2 constraint). The base case assigns dp[{c}][c]=1\mathrm{dp}[\{c\}][c] = 1 for each column cc. Each transition extends a valid partial placement by one row. By induction on mask|\mathrm{mask}|, dp[mask][c]\mathrm{dp}[\mathrm{mask}][c] counts all valid partial placements of mask|\mathrm{mask}| queens using columns mask\mathrm{mask} with the last in column cc. Summing over all cc when mask=2n1\mathrm{mask} = 2^n - 1 gives f(n)f(n). \square

Editorial

A weak queen attacks only adjacent squares (king moves). Place n non-attacking weak queens on an n x n board, one per row. Constraint: queens in adjacent rows must be >= 2 columns apart. Compute sum_{n=1}^{12} f(n) using bitmask DP.

Pseudocode

    if n == 1: return 1
    if n <= 3: return 0

    dp[mask][last_col] = count of valid placements
    dp = map from (mask, col) -> integer, initially 0
    For c from 0 to n-1:
        dp[(1 << c, c)] = 1

    For row from 1 to n-1:
        new_dp = empty map
        For each each (mask, prev_c) in dp with popcount(mask) == row:
            For c from 0 to n-1:
                If mask & (1 << c) != 0 then continue
                If |c - prev_c| < 2 then continue
                new_dp[(mask | (1 << c), c)] += dp[(mask, prev_c)]
        merge new_dp into dp

    Return sum of dp[(2^n - 1, c)] for all c

    Return sum of F(n) for n = 1 to 12

Complexity Analysis

  • Time: O(n22n)O(n^2 \cdot 2^n) per value of nn. For each of the O(n2n)O(n \cdot 2^n) states, we try O(n)O(n) transitions. For n=12n = 12: 122212=589,82412^2 \cdot 2^{12} = 589{,}824 operations. Summing over n=1,,12n = 1, \ldots, 12 is dominated by the n=12n = 12 term.
  • Space: O(n2n)O(n \cdot 2^n) for the DP table. For n=12n = 12: 124096=49,15212 \cdot 4096 = 49{,}152 entries.

Answer

11726115562784664\boxed{11726115562784664}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_534/solution.cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

/*
 * Problem 534: Weak Queens
 *
 * Place n non-attacking weak queens (king-move attacks only) on n x n board.
 * One queen per row. Queens in adjacent rows must differ by >= 2 columns.
 *
 * Bitmask DP: dp[mask][last_col] = count of ways.
 * Time: O(n^2 * 2^n).
 */

ll f(int n) {
    if (n <= 0) return 0;
    if (n == 1) return 1;

    int total_masks = 1 << n;
    // dp[mask][last_col]
    vector<vector<ll>> dp(total_masks, vector<ll>(n, 0));

    // Row 0: place queen in any column
    for (int c = 0; c < n; c++) {
        dp[1 << c][c] = 1;
    }

    for (int row = 1; row < n; row++) {
        vector<vector<ll>> new_dp(total_masks, vector<ll>(n, 0));
        for (int mask = 0; mask < total_masks; mask++) {
            if (__builtin_popcount(mask) != row) continue;
            for (int prev_c = 0; prev_c < n; prev_c++) {
                if (dp[mask][prev_c] == 0) continue;
                for (int c = 0; c < n; c++) {
                    if (mask & (1 << c)) continue;
                    if (abs(c - prev_c) < 2) continue;
                    new_dp[mask | (1 << c)][c] += dp[mask][prev_c];
                }
            }
        }
        for (int mask = 0; mask < total_masks; mask++) {
            for (int c = 0; c < n; c++) {
                dp[mask][c] += new_dp[mask][c];
            }
        }
    }

    int full = (1 << n) - 1;
    ll result = 0;
    for (int c = 0; c < n; c++) {
        result += dp[full][c];
    }
    return result;
}

int main() {
    ll total = 0;
    for (int n = 1; n <= 12; n++) {
        ll val = f(n);
        printf("f(%d) = %lld\n", n, val);
        total += val;
    }
    printf("Sum = %lld\n", total);
    assert(total == 3884);
    cout << total << endl;
    return 0;
}