バックトラッキングによるN-Queens問題の詳細解析と可視化
N-Queens問題は、N×Nのチェス盤上にN個のクイーンを、互いに攻撃し合わないように配置する問題です。この問題をバックトラッキング手法で解決します。
/**
* N-Queens問題を解く関数
* @param {number} n - チェス盤のサイズ (1 <= n <= 9)
* @returns {string[][]} - 全ての有効なクイーン配置を返す
*
* 時間計算量: O(N!) - バックトラッキングで全探索
* 空間計算量: O(N^2 * 解の個数) - 盤面保存のため
*/
function solveNQueens(n: number): string[][] {
const results: string[][] = [];
// 現在の盤面を '.' で初期化
const board: string[][] = Array.from({ length: n }, () =>
Array(n).fill('.')
);
// 使用済みの列・対角線を記録する集合(O(1)チェックのため)
const cols: Set = new Set(); // 同じ列
const diag1: Set = new Set(); // 左上→右下 (row-col)
const diag2: Set = new Set(); // 右上→左下 (row+col)
/**
* バックトラッキング探索
* @param {number} row - 現在の行
*/
function backtrack(row: number): void {
// ベースケース: 全ての行にクイーンを配置完了
if (row === n) {
const solution: string[] = board.map(r => r.join(''));
results.push(solution);
return;
}
// 現在の行の各列を試行
for (let col = 0; col < n; col++) {
// 攻撃範囲チェック(O(1)時間)
if (cols.has(col) ||
diag1.has(row - col) ||
diag2.has(row + col)) {
continue; // 制約違反のためスキップ
}
// クイーンを配置
board[row][col] = 'Q';
cols.add(col);
diag1.add(row - col);
diag2.add(row + col);
// 次の行を再帰探索
backtrack(row + 1);
// バックトラック: 状態を元に戻す
board[row][col] = '.';
cols.delete(col);
diag1.delete(row - col);
diag2.delete(row + col);
}
}
backtrack(0); // 0行目から開始
return results;
}
行: 0
列: -
試行回数: 0
バックトラック回数: 0
使用済み列: なし
対角線1: なし
対角線2: なし
| 項目 | 計算量 | 説明 |
|---|---|---|
| 時間計算量 | O(N!) |
最悪の場合、各行でN個の位置を試行する必要があり、実際はそれより少ない |
| 空間計算量 | O(N) |
再帰スタック、制約セット、盤面配列で線形空間 |
| 制約チェック | O(1) |
Setを使用することで定数時間での制約確認が可能 |
| 解の格納 | O(N² × 解の個数) |
各解をN×Nの文字列配列として保存 |
cols, diag1, diag2 のSetを使用してO(1)時間での制約確認を実現。
従来のO(N)チェックから大幅に高速化。
(row - col) と (row + col) で表現することで、
効率的な対角線制約管理が可能。