逐行放置皇后,用三个数组(列、主对角线、副对角线)检测冲突,回溯搜索所有合法方案。
OJ: leetcodecn
题目 ID: n-queens
难度:普及+/提高
标签:回溯枚举递归
日期: 2026-07-29 11:40
题意
在
思路
最直接的思路是枚举每行皇后放在哪一列,全部决定后再检查冲突:
cpp
// brute.cpp:小数据暴力解,递归枚举每一行的皇后放在哪一列。
#include <bits/stdc++.h>
using namespace std;
int n;
int place[10]; // place[r] = c 表示第 r 行皇后在第 c 列
vector<vector<string>> ans;
bool check() {
for (int r1 = 0; r1 < n; r1++)
for (int r2 = r1 + 1; r2 < n; r2++)
if (place[r1] == place[r2] || abs(place[r1] - place[r2]) == r2 - r1)
return false;
return true;
}
void dfs(int r) {
if (r == n) {
if (check()) {
vector<string> board(n, string(n, '.'));
for (int i = 0; i < n; i++)
board[i][place[i]] = 'Q';
ans.push_back(board);
}
return;
}
for (int c = 0; c < n; c++) {
place[r] = c;
dfs(r + 1);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
dfs(0);
for (auto &v : ans) {
for (auto &s : v)
cout << s << '\n';
cout << '\n';
}
return 0;
}brute.cpp 先生成完整排列再检查冲突,复杂度
优化的关键是:逐行放置时用三个冲突集合实时剪枝。
col[c]:第c列是否已有皇后。diag1[r+c]:主对角线(左上到右下)是否已有皇后。同一主对角线上的格子满足r+c相等。diag2[r-c+n-1]:副对角线(右上到左下)是否已有皇后。同一副对角线上的格子满足r-c相等(偏移n-1避免负下标)。
每行只放一个皇后,所以行冲突天然不存在。三个数组实时标记当前占据的列和对角线,放置前检查、放置后标记、递归后恢复,保证每一步只扩展合法分支。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> ans;
vector<int> col(n), diag1(2 * n - 1), diag2(2 * n - 1);
vector<string> board(n, string(n, '.'));
function<void(int)> dfs = [&](int r) {
if (r == n) {
ans.push_back(board);
return;
}
for (int c = 0; c < n; c++) {
// 同一主、副对角线上的格子分别共享 r+c 和 r-c+n-1。
int d1 = r + c, d2 = r - c + n - 1;
if (col[c] || diag1[d1] || diag2[d2])
continue;
col[c] = diag1[d1] = diag2[d2] = 1;
board[r][c] = 'Q';
dfs(r + 1);
board[r][c] = '.';
col[c] = diag1[d1] = diag2[d2] = 0;
}
};
dfs(0);
return ans;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (auto &v : Solution().solveNQueens(n)) {
for (auto &s : v)
cout << s << '\n';
cout << '\n';
}
return 0;
}python
#!/usr/bin/env python3
from typing import List
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
ans, board = [], ["." * n for _ in range(n)]
col, d1, d2 = [0] * n, [0] * (2 * n - 1), [0] * (2 * n - 1)
def dfs(r):
if r == n:
ans.append(board[:])
return
for c in range(n):
if col[c] or d1[r + c] or d2[r - c + n - 1]:
continue
col[c] = d1[r + c] = d2[r - c + n - 1] = 1
lst = list(board[r])
lst[c] = "Q"
board[r] = "".join(lst)
dfs(r + 1)
lst[c] = "."
board[r] = "".join(lst)
col[c] = d1[r + c] = d2[r - c + n - 1] = 0
dfs(0)
return ans
def main():
n = int(input())
for v in Solution().solveNQueens(n):
for s in v:
print(s)
print()
if __name__ == "__main__":
main()复杂度
- 时间复杂度:
,第一行 n 个选择,第二行最多 n-1 个,逐行递减。 - 空间复杂度:
,三个冲突数组加递归栈。
总结
N 皇后是回溯剪枝的经典模型。关键是用 col、diag1、diag2 三个数组将冲突检测从 r+c,副对角线 r-c+n-1,使得同一对角线上所有格子的下标相等。