原题链接如下:
AcWing 843. n-皇后问题
来自y总算法基础课第三讲搜索与图论,而n-皇后问题众所周知是dfs的典型问题
原题详细如下:
n− 皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
现在给定整数 n,请你输出所有的满足条件的棋子摆法。
输入格式
共一行,包含整数 n。
输出格式
每个解决方案占 n 行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。
其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。
每个方案输出完成后,输出一个空行。
注意:行末不能有多余空格。
输出方案的顺序任意,只要不重复且没有遗漏即可。
数据范围
1≤n≤9
输入样例:
4
输出样例:
.Q..
...Q
Q...
..Q.
..Q.
Q...
...Q
.Q..
参考代码:
#include<iostream>
using namespace std;
const int N = 20;
int n;
char g[N][N];//存放题目所需的棋盘 每个槽初始值默认为.
bool col[N],dg[N],udg[N];//记录当前列,当前正对角线,当前反对角线使用过否
void dfs(int u)
{
//到达递归的结束的边界 输出放置好皇后的地图
if(u==n)
{
for(int i = 0;i<n;i++) puts(g[i]);
puts("");
return;//不要忘记return 不然会无休止的运行 更不会回溯
}
//尝试每一列的可能
for(int i = 0;i<n;i++)
{
//判断横行u和竖列i构成的坐标(u,i) 在这列 在这正对角线和反对角线是否放置了皇后
if(!col[i]&& !udg[u+i]&& !dg[u-i+n])
{
g[u][i] = 'Q';
col[i] = udg[u+i] = dg[u-i+n] = true;//标记这个放过皇后的点
dfs(u+1);//继续到下一行中的位置
col[i] = udg[u+i] = dg[u-i+n] = 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;
}
问题解析:
n-皇后问题的核心就是将每个位置进行试探,保证每个皇后不在同一列,不在同一对角线,也不在同一反对角线。这个试探的过程其实就是深度优先搜索bfs的过程,我们通过bfs把每一行可能在哪个地方放置皇后的方案都进行了搜索并且输出,所以我们能达到题目中要求的输出每一种可能的解决方案。
重点细节解析:
核心函数:void dfs(int u)
边界情况:
//到达递归的结束的边界 输出放置好皇后的地图
if(u==n)
{
for(int i = 0;i<n;i++) puts(g[i]);
puts("");
return;//不要忘记return 不然会无休止的运行 更不会回溯
}
对当前行中的列的每一个可能值的尝试
for(int i = 0;i<n;i++)
{
...
}
剪枝过程:
if(!col[i]&& !dg[u+i]&& !udg[n-u+i])
剪枝就是为了减少搜索树的规模,因为当发现某个位置不能防止皇后,我们就跳过寻找下一个列位置,不然用这个错误的位置还往下走搜寻是多余的,再继续下去也是错误的。
剪枝的实现思路:我们采用的是一元一次方程,我们利用正反对角线在函数上的特性,整个棋盘我们看成一个平面直角坐标系,u代表横行的话就相当于y坐标,i代表列的话就相当于x坐标,则正对角线方程为u = i+b
,即b = u-i
,同时应该注意的是u-i
可能是负数,所以我们需要加个偏移量n
,保证参数为正。的而反对角线方程为 u = b - i
,即b = u+i
虽然u和i的值在不断变化,但是总和是不变的,因此会形成两条正反对角线。对于相减可能为负的情况,添加偏移量n。所以就可以用这种方式来搜素各个位置的状态。
for(int i = 0;i<n;i++)
{
//判断横行u和竖列i构成的坐标(u,i) 在这列 在这正对角线和反对角线是否放置了皇后
if(!col[i]&& !udg[u+i]&& !dg[u-i+n])
{
g[u][i] = 'Q';
col[i] = udg[u+i] = dg[u-i+n] = true;//标记这个放过皇后的点
dfs(u+1);//继续到下一行中的位置
col[i] = udg[u+i] = dg[u-i+n] = false;//恢复现场
g[u][i] = '.';
}
}
至此,基本上这个问题关键问题都给解决了,本人讲解能力有限,感兴趣的同学们可以去AcWing官网看看大佬们的题解,就在原题链接的题解部分