n−皇后问题是指将 n个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
此题目的重点在于判断当前搜索位置的行列和斜线是否存在其他皇后。行列很好判断,构建一个布尔函数即可,难点是对于斜线的判断。右下方向的斜线可以抽象为坐标轴上y=-x+b的函数,这样我们通过简单的变换就知道b=x+y的关系,如此得出结论横纵坐标的和是一个固定值,立足于此我们就可以构建布尔函数判断。同样右上方向的斜线得到b=y-x的关系,但是有可能y-x等于一个负值。为了避免这种情况,我们可以加上一个n,即b=y-x+n。
dfs具体的搜索思路有两种:
1、按照格子数一个一个搜
#include<iostream>
#include<cstdio>
using namespace std;
#define N 20
int n;
char q[N][N];
bool a[N],b[N],c[N],d[N];
void dfs(int x,int y,int z)//变量分别是横纵坐标和已经放入的皇后数目
{
if(y==n) y=0,x++;//当列数到边界后,换行的同时让列数从头开始
if(x==n)//当行数到边界后,判断是否每一个皇后都放入了棋盘,如果都放进去了就输出结果
{
if(z==n)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<q[i][j];
}
puts("");
}
puts("");//注意题目要求的空行问题
}
return;
}
dfs(x,y+1,z);//在当前位置选择不放入皇后
if(!a[x]&&!b[y]&&!c[x+y]&&!d[n+y-x])//在当前位置选择放入皇后
{
a[x]=b[y]=c[x+y]=d[n+y-x]=true;
q[x][y]='Q';
dfs(x,y+1,z+1);
a[x]=b[y]=c[x+y]=d[n+y-x]=false;
q[x][y]='.';
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
q[i][j]='.';
}
dfs(0,0,0);
return 0;
}
2、按照行一行一行搜(更优解)
#include<iostream>
#include<cstdio>
using namespace std;
#define N 20
int n;
bool a[N],b[N],c[N];//此处不必再判断同行问题,因为搜索是一行一行来的,同一行不可能出现多个皇后
char q[N][N];
void dfs(int x)
{
if(x==n)//当行数到边界,输出结果
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<q[i][j];
}
puts("");
}
puts("");
}
for(int i=0;i<n;i++)
{
if(!a[i]&&!b[x+i]&&!c[n+i-x])
{
a[i]=b[i+x]=c[n+i-x]=true;
q[x][i]='Q';
dfs(x+1);
a[i]=b[i+x]=c[n+i-x]=false;
q[x][i]='.';
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
q[i][j]='.';
dfs(0);
return 0;
}