校赛考到忘了,赶紧回来复习一遍(结果发现上次理解的有问题呜呜呜,警示后人)
首先n皇后是标准的DFS这个没得说
主要的难点在于剪枝的判断:
已知任意两个皇后不能在同一排,同一列以及同一对角线,所以对剪枝的判断得从标记行、列和
对角线考虑,因为如果只是单纯标记已经摆放的位置,就无法实现剪枝判断所覆盖的范围(即一列、
两条对角线)
于是我们设置三个布尔数组row[],dg[]和udg[],分别表示列,左对角线和右对角线
由于不同列是很好表示的(即当前位置的y坐标),所以关键在于左右对角线的表示
而我们发现,棋盘上的对角线是这样的:
将棋盘左下角作为原点构建直角坐标系,我们可以得到,实际上左右对角线分别是a = 1和a = -1的线性函数图像
那么便可以这样分析:
代码(这里只展示第一种形式的枚举):
#include <iostream>
#include <cmath>
using namespace std;
const int N = 15;
char a[N][N];
bool dg[N];//对应列
bool edg[2 * N];//对应对角线(由于正负截距均有对角线,所以要开两倍空间大小)
bool udg[2 * N];//对应反对角线
int n;
//初始化
void st(){
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
a[i][j] = '.';
}
}
}
void dfs(int step){
if(step == n){
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
cout << a[i][j];
}
cout << endl;
}
cout << endl;
}
for(int i = 0;i < n;i++){
//用截距作为下标标记对角线
//枚举每一列
if(!dg[i] && !udg[i + step] && !edg[n - step + i]){
a[step][i] = 'Q';
dg[i] = udg[i + step] = edg[n - step + i] = true;
dfs(step + 1);
dg[i] = udg[i + step] = edg[n - step + i] = false;//回溯
a[step][i] = '.';
}
}
}
int main(){
cin >> n;
st();
dfs(0);
return 0;
}