给定一个大小为 n 的正方形国际象棋棋盘,求有多少种方式可以放置 n 个皇后并使得她们互不攻击,即每一行、列、左斜、右斜最多只有一个皇后。
输入是一个整数 n,输出是一个整数 m,表示所有的棋盘表示方法。
/**
* 假设第一行皇后摆放在坐标(0, 1)
0 1(Q) 2 3
|
|
0 —— —— 1 —— —— 2 3
现在需要摆放第二行,第一行与第二行的行差值为一,这里是个等腰三角形
所以左斜线位置为(x, 1 - 1 = 0),右斜线位置为(x, 1 + 1 = 2),同理可计算出其他行之间的关系
0 1 2 3
0 1 2 3
*/
function func(n) {
// 记录有几种摆法
let count = 0;
// 记录每一行的皇后所在的位置
let queens = new Array(n).fill(0);
const _getQueens = row => {
// 记录该行皇后不可摆放的位置
let visited = new Array(n).fill(false);
// 遍历第一行到该行,皇后已经摆放的位置,遍历行
for (let i = 0; i < row; ++i) {
// 之前摆放过的位置不能再次摆放
visited[queens[i]] = true;
// 计算斜线差值,即行高
let sub = row - i;
// 左斜线不能再次摆放,不能越界
if (queens[i] - sub >= 0) {
visited[queens[i] - sub] = true;
}
// 右斜线不能再次摆放,不能越界
if (queens[i] + sub <= n - 1) {
visited[queens[i] + sub] = true;
}
}
// 至此得到了该行所有不可摆放的位置
// 尝试在剩下的可选位置中进行摆放,遍历列
for (let i = 0; i < n; ++i) {
// 不可摆放的位置,跳出
if (visited[i]) {
continue;
}
// 尝试该行摆放皇后,所以若此次失败,会被后续的迭代所覆盖
queens[row] = i;
// 递归处理下一行
if (row < n - 1) {
_getQueens(row + 1);
} else {
// 行数已至最末行,说明这种摆法成功,记录
++count;
}
}
};
// 从第一行开始遍历
_getQueens(0);
return count;
}
// 四皇后有 2 种摆法
// 八皇后有 92 种摆法
const result = func(8);
console.log(result);
/**
* 同行:x1 = x2
同列:y1 = y2
斜线正方向(/):x1 + y1 = x2 + y2
斜线反方向(\):x1 - y1 = x2 - y2
*/
function func(n) {
const res = [];
// n * n 的棋盘,有 2 * n - 1 条斜线
const arr = [];
for (let i = 0; i < n; ++i) {
arr[i] = new Array(n).fill('+');
}
// 已摆放的位置
const queens = new Array(n).fill(false);
// 左斜线(/)已摆放的位置
const ldiag = new Array(2 * n - 1).fill(false);
// 右斜线(\)已摆放的位置
const rdiag = new Array(2 * n - 1).fill(false);
const _getQueens = row => {
// 遍历到最末行,说明这次摆法成功
if (row == n) {
res.push(JSON.parse(JSON.stringify(arr)));
return;
}
// 遍历该行的每一列
for (let i = 0; i < n; ++i) {
// 这一列或左斜线或右斜线不可摆放时,跳过
if (queens[i] || ldiag[row + i] || rdiag[row - i]) {
continue;
}
// 尝试摆放皇后的位置并记录
arr[row][i] = 'Q';
queens[i] = true;
ldiag[row + i] = true;
rdiag[row - i] = true;
// 递归下一行
_getQueens(row + 1);
// 成功或失败,回退至上一步的选择,继续尝试判断该行的下一列是否可以摆放
arr[row][i] = '+';
queens[i] = false;
ldiag[row + i] = false;
rdiag[row - i] = false;
}
};
// 从第一行开始遍历
_getQueens(0);
return res;
}
const result = func(4);
console.log(result, result.length);