n−皇后问题是指将 n个皇后放在 n×n的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
现在给定整数 n,请你输出所有的满足条件的棋子摆法。
输入格式
共一行,包含整数 n
输出格式
每个解决方案占 n行,每行输出一个长度为 n的字符串,用来表示完整的棋盘状态。
其中 .
表示某一个位置的方格状态为空,Q
表示某一个位置的方格上摆着皇后。
每个方案输出完成后,输出一个空行。
注意:行末不能有多余空格。
输出方案的顺序任意,只要不重复且没有遗漏即可。
数据范围
1≤n≤9
输入样例:
4
输出样例:
.Q..
...Q
Q...
..Q.
..Q.
Q...
...Q
.Q..
✨思路一
先讲原始方法,好理解一点,DFS按每个元素枚举 ,因为每个位置都有两种情况,总共有 n2
2
个位置先看代码主要是dfs ,代码看不懂的话,往下看c++代码:
#include <iostream>
using namespace std;
const int N = 20;//对角线元素 2n-1 取20防止越界
int n;
char g[N][N]; //存储图
bool row[N],col[N], dg[N], udg[N]; //udg 副对角线 /
//英语单词 column 列 diagonal 主角线 \
//row 行
void dfs (int x,int y,int s) { //xy为坐标 (x,y) s为 n皇后放置个数
if (y == n) { //当x走到行末尾的时候
y = 0; //转到下一行的第一个
x++;
}
if (x == n) { //走到最后一行 且n皇后都放好的时候
if (s == n) { // 如果找到方案的话
for (int i = 0; i < n; i ++) {
puts(g[i]);//puts输出二维数组 输出每一行如何就会自动换行
}//puts遍历字符串这个语法不懂看下
puts("");
}
return; //返回调用函数进行执行
}
dfs(x, y + 1, s);//不放皇后 并且访问右节点
// 判断皇后能否放在这格
if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n]) {
g[x][y] = 'Q';//放皇后 然后把
row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
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); //从(0,0)开始找
return 0;
}
代码剖析
主副对角线是线性代数的内容,看不懂的话自行百度
图片看不了 点这个链接
row数组的理解
这个图的主副对角线画反了,自行更正下
dg[x + y] = udg[y - x + n]的理解
dg[x + y] = udg[y - x + n] 有的兄弟可能不理解其中x+y到底是什么意思?
以反对角线举例,y - x其实就是该点在对角线上的截距 由中学知识可知对角线方程为y = x + b,其中b表示截距也就是b = y - x(数组下标里面的东西),如果在不同行,但再同一对角线,经过方程计算得到的截距都是一样的,不懂就拿纸自己写一下,+n是为了防止负数产生, 因为数组下标是不可能为负数的,因为每个数都+n,他们映射到结果是一样的,不信你就换个比n大的数试试。
✨思路二
这思路排列数字类似,算法效率比思路一高,主要是运用了剪枝算法;提前判断当前方案已经错误,不再继续往下搜索,提高算法效率
#include <iostream>
using namespace std;
const int N = 20;//对角线元素 2n-1 取20防止越界
int n;
char g[N][N]; //存储图
bool col[N], dg[N], udg[N]; //udg 副对角线 /
//英语单词 column 列 diagonal 主角线 \
void dfs (int x) {
if (x == n) { // 如果找到方案的话
for (int i = 0; i < n; i ++) {
puts(g[i]);//puts输出二维数组 输出每一行如何就会自动换行
}
puts("");
return; //返回调用函数进行执行
}
/* puts语句不理解 可以看下面这个 作用是一样的
if (x == n) {
for (int i = 0; i < n; i ++) {
for (int j = 0; j < n; j ++) {
cout << g[i][j];
}
cout << endl;
}
cout << endl ;
return;
}
*/
//x:行 y:列
for (int y = 0; y < n; y ++) {
//按行枚举 因为每一行都需要放皇后 相当于剪枝了
// 剪枝(提前判断当前方案已经错误,不再继续往下搜索,提高算法效率)
// 判断皇后能否放在这格
if (!col[y] && !dg[x + y] && !udg[y - x + n]) {
g[x][y] = 'Q';
col[y] = dg[x + y] = udg[y - x + n] = true;
dfs(x + 1);//找下一层的
//回溯的时候 记得恢复现场
col[y] = dg[x + y] = udg[y - x + 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:下标]
return 0;
}