class Solution {
public:
vector<vector<string>> ans; // 存储最终结果
vector<vector<string>> solveNQueens(int n) {
vector<int> queens(n, 0); // 记录每行皇后放置的列索引
vector<int> col(n, 0); // 记录列是否被占用
vector<int> diag1(2 * n - 1, 0); // 记录主对角线是否被占用
vector<int> diag2(2 * n - 1, 0); // 记录副对角线是否被占用
solveQueens(queens, col, diag1, diag2, 0, n); // 递归回溯求解
return ans;
}
void solveQueens(vector<int> &queens, vector<int> &col, vector<int> &diag1, vector<int> &diag2, int r, int n) {
if (r == n) { // 所有行都成功放置皇后
vector<string> res(n, string(n, '.')); // 生成 n*n 棋盘
for (int i = 0; i < n; i++) {
res[i][queens[i]] = 'Q'; // 放置皇后
}
ans.push_back(res); // 存入答案
return;
}
for (int c = 0; c < n; c++) {
if (col[c] == 1 || diag1[r + c] == 1 || diag2[r - c + n - 1] == 1) continue; // 剪枝
// 放置皇后并标记
queens[r] = c;
col[c] = 1;
diag1[r + c] = 1;
diag2[r - c + n - 1] = 1;
solveQueens(queens, col, diag1, diag2, r + 1, n); // 递归进入下一行
// 回溯,撤销选择
col[c] = 0;
diag1[r + c] = 0;
diag2[r - c + n - 1] = 0;
}
}
};
• 同一列不能有两个皇后
• 同一行不能有两个皇后(递归中,每次放置一个皇后在新的一行,因此不需要额外检查)
• 同一主对角线不能有两个皇后(r + c 唯一)
• 同一副对角线不能有两个皇后(r - c 唯一)
我们采用 回溯(Backtracking)+ 状态数组 来求解:
1. 用递归函数 solveQueens(r) 逐行放置皇后:
• 若 r == n,说明所有行都放置了皇后,将解法加入 ans。
• 遍历 c = 0 到 n-1 作为列,尝试在 (r, c) 放置皇后:
• 若当前位置可行(不与之前的皇后冲突),则标记 col[c], diag1[r + c], diag2[r - c + n - 1],然后递归求解 r + 1 行。
• 回溯:撤销本次选择,尝试下一个可能位置。
好的,我们一步步详细讲解 N 皇后 问题的执行流程,并展示 每次递归调用的变化,确保你完全理解它的运行方式。
🌟 问题分析
我们要在 N×N 的棋盘上放置 N 个皇后,并保证它们 不在同一行、同一列、同一主对角线或同一副对角线。
🌟 执行步骤解析(以 N=4 为例)
🚀 1. 初始状态
我们从 r=0 开始,尝试在第一行 r=0 放置皇后。
棋盘:
. . . . ← (r=0, 还未放置)
. . . .
. . . .
. . . .
🚀 2. 递归步骤
👉 尝试在 r=0 放置皇后
我们尝试在 (0,0) 放置皇后:
Q . . . ← 放置皇后 (0,0)
. . . .
. . . .
. . . .
• 更新 col[0] = 1 (列 0 被占用)
• 更新 diag1[0+0] = 1 (主对角线 r+c=0 被占用)
• 更新 diag2[0-0+3] = 1 (副对角线 r-c+n-1=3 被占用)
👉 递归到 r=1
我们在 r=1 试图放置皇后。
• c=0 不能放(因为 col[0] = 1,列冲突)
• c=1 不能放(因为 diag1[1+1] = 1,主对角线冲突)
• c=2 可以放(无冲突)
Q . . . ← (0,0)
. . Q . ← 放置 (1,2)
. . . .
. . . .
更新:
• col[2] = 1
• diag1[1+2] = 1
• diag2[1-2+3] = 1
👉 递归到 r=2
在 r=2 试图放置皇后:
• c=0 可以放(无冲突)
Q . . . ← (0,0)
. . Q . ← (1,2)
. Q . . ← 放置 (2,1)
. . . .
更新:
• col[1] = 1
• diag1[2+1] = 1
• diag2[2-1+3] = 1
👉 递归到 r=3
在 r=3 试图放置皇后:
• c=0 不能放
• c=1 不能放
• c=2 不能放
• c=3 可以放
Q . . . ← (0,0)
. . Q . ← (1,2)
. Q . . ← (2,1)
. . . Q ← 放置 (3,3)
• 找到一个解!存储到 ans
🚀 3. 回溯
我们回溯:
• 撤销 (3,3) → 继续尝试 r=3(无其他选项,回溯 r=2)
• 撤销 (2,1) → 继续尝试 r=2
• 撤销 (1,2) → 继续尝试 r=1
继续寻找新解……
最终得到 两个解:
1. Q . . . 2. . Q . .
. . Q . . . . Q
. . . Q Q . . .
. Q . . . . Q .
🌟 复杂度分析
• 时间复杂度:O(N!),回溯会尝试所有可能的皇后排列,但因为剪枝,效率比 N! 好很多。
• **空间复杂度:O(N)**,只用 col, diag1, diag2` 记录状态。
🌟 总结
1. 递归逐行放置皇后
2. 检查列、主对角线、副对角线是否冲突
3. 放置皇后并递归到下一行
4. 所有行完成时,存储解法
5. 回溯撤销选择,继续尝试其他列
6. 最终输出所有解
这样,你能清楚地理解 N 皇后问题的求解过程了吗? 😃