题目地址:
https://www.acwing.com/problem/content/845/
n n n皇后问题,在 n × n n\times n n×n的棋盘上放 n n n个皇后,使得这些皇后互相不攻击。要求输出所有方案。
输入格式:
共一行,包含整数
n
n
n。
输出格式:
每个解决方案占
n
n
n行,每行输出一个长度为
n
n
n的字符串,用来表示完整的棋盘状态。其中”.”表示某一个位置的方格状态为空,”Q”表示某一个位置的方格上摆着皇后。每个方案输出完成后,输出一个空行。注意:行末不能有多余空格。输出方案的顺序任意,只要不重复且没有遗漏即可。
数据范围:
1
≤
n
≤
9
1\le n\le 9
1≤n≤9
思路是DFS。枚举每一行在哪一列放皇后。同时用三个变量分别存,哪些列已经放了皇后,还有哪些对角线已经放了皇后。对于对角线的判断,我们可以分为方向从左上到右下的对角线,和方向从右上到左下的对角线两种类型分别判断。从左上到右下的对角线,我们规定 ( 0 , n − 1 ) (0,n-1) (0,n−1)所在的对角线是 0 0 0号, ( 0 , n − 2 ) (0,n-2) (0,n−2)所在的对角线是 1 1 1号,等等,那么对角线的号码 k k k和上面某点的坐标 ( i , j ) (i,j) (i,j)满足 j = i + n − 1 − k j=i+n-1-k j=i+n−1−k,所以 k = i − j + n − 1 k=i-j+n-1 k=i−j+n−1;从右上到左下的对角线,我们规定 ( 0 , 0 ) (0,0) (0,0)所在的对角线是 0 0 0号, ( 0 , 1 ) (0,1) (0,1)所在的对角线是 1 1 1号,等等,那么对角线的号码 k k k和上面某点的坐标 ( i , j ) (i,j) (i,j)满足 j = − i + k j=-i+k j=−i+k,所以 k = i + j k=i+j k=i+j。搜到第 n + 1 n+1 n+1行的时候说明找到了一个解,输出答案即可。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
void dfs(int i, int res[], int n, bool used[], bool diag[], bool udiag[]) {
if (i == n) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
if (res[j] == k) cout << 'Q';
else cout << '.';
}
cout << endl;
}
cout << endl;
return;
}
for (int j = 0; j < n; j++) {
if (used[j] || diag[i - j + n - 1] || udiag[i + j]) continue;
used[j] = diag[i - j + n - 1] = udiag[i + j] = true;
res[i] = j;
dfs(i + 1, res, n, used, diag, udiag);
used[j] = diag[i - j + n - 1] = udiag[i + j] = false;
}
}
int main() {
int n;
cin >> n;
int res[n];
bool used[n], diag[2 * n - 1], udiag[2 * n - 1];
memset(used, false, sizeof used);
memset(diag, false, sizeof diag);
memset(udiag, false, sizeof udiag);
dfs(0, res, n, used, diag, udiag);
return 0;
}
时间复杂度 O ( n 2 n ! ) O(n^2n!) O(n2n!)(因为伴随着剪枝,实际时间达不到这么高),空间 O ( n ) O(n) O(n)。