题目描述
n− 皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
现在给定整数 n,请你输出所有的满足条件的棋子摆法。
输入格式
共一行,包含整数 n。
输出格式
每个解决方案占 n 行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。
其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。
每个方案输出完成后,输出一个空行。
注意:行末不能有多余空格。
输出方案的顺序任意,只要不重复且没有遗漏即可。
数据范围
1≤n≤9
输入样例:
4
输出样例:
.Q..
...Q
Q...
..Q.
..Q.
Q...
...Q
.Q..
方法一:按照全排列的方法来枚举所有可能
可以将全排列中的位数看作皇后在第几行,数值看作在第几列,因此枚举所有的全排列就是枚举所有可能出现的皇后的位置。可以枚举一个全排列后进行判断是否满足皇后问题的条件。也可以提前退出,对于这个题目来说,只要出现了不满足条件的数那么这个全排列方案就一定不满足了(剪枝儿)
时间复杂度:
n * n!
难点:
感觉这个题目的难点在于对是否满足条件的判断,题目要求两个皇后不能在同一行、列、对角线上,
- 行和列很好处理,设置一个bool数组,在枚举列的时候,使用到了这一列,就标记一下
- 对于对角线,就是找规律吧,对于对角线来说,可以通过截距来确定一条对角线,而截距可以通过坐标值来计算出,所以只要一个截距出现过一次,就标记一下
代码
#include <iostream>
using namespace std;
const int N = 20;
char g[N][N];
bool col[N], dg[N], udg[N];
int n;
void dfs(int u)
{
if (u == n)
{
for (int i = 0; i < n; i ++) puts(g[i]);
puts("");
return;
}
// u代表行,i代表列
for (int i = 0; i < n; i ++)
if (!col[i] && !dg[i - u] && !udg[i + u])
{
col[i] = dg[i - u] = udg[i + u] = true;
g[u][i] = 'Q';
dfs(u + 1);
col[i] = dg[i - u] = udg[i + u] = false;
g[u][i] = '.';
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++)
for (int j = 0; j < n; j ++)
g[i][j] = '.';
dfs(0);
return 0;
}
方法二:枚举所有的格子
时间复杂度
2 ^ n^2
参考文献
C++ 代码
#include <iostream>
using namespace std;
const int N = 20;
int n;
char g[N][N];
bool row[N], col[N], dg[N], udg[N];
void dfs(int x, int y, int s)
{
if (y == n) y = 0, x ++;
if (x == n)
{
if (s == n)
{
for (int i = 0; i < n; i ++) puts(g[i]);
puts("");
}
return;
}
// 不放皇后
dfs(x, y + 1, s);
// 放皇后
if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n])
{
row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
g[x][y] = 'Q';
dfs(x, y + 1, s + 1);
row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
g[x][y] = '.';
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++)
for (int j = 0; j < n; j ++)
g[i][j] = '.';
dfs(0, 0, 0);
return 0;
}