八皇后问题是一个经典的问题, 在一个8 × 8 的棋盘上, 每行刚好放置一个并不能互相攻击(同一行,同一列,同一斜线上的皇后都会自动攻击)。
上图就是一个合法的八皇后的解。
利用数组标记已筛选皇后的同一行,同一列,同一斜线上, 那么同一行,同一列,同一斜线上的位置将不能放置皇后。
同一行,同一列的标记,但最难处理的是同一斜线的标记, 可以通过暴力枚举,但有一种更巧妙地方法。
这条对角线的位置的行加列的值相同, 都是4。
即 0 + 4 = 1 + 3 = 2 + 2 = 3 + 1 = 4 + 0 = 4
而这样的对角线的位置的坐标的行减去列的值也是相同的, 都是 - 2。
接下来可以判断第 c 列第 i 行的位置是否可以放下皇后,在这之前我们要标记。
标记列 row[ i ] = ture;
标记第一条对角线 x1[ c+i ] = true;
标记第二条对角线 x2[ c - i + 8 ] = true;
row[i] = x1[c+i] = x2[c-i+8] = true;
注意:回溯要取消标记
row[i] = x1[c+i] = x2[c-i+8] = false;
然后写个布尔类型的check函数来判断当前位置到底能不能放皇后
bool check(int c, int i){
return !row[i] && !x1[c+i] && !x2[c-i+8];
}
开始搜索。
for(int i=0; i<8; i++){
if(check(c, i)){
row[i] = x1[c+i] = x2[c-i+8] = true;
dfs(c+1);
row[i] = x1[c+i] = x2[c-i+8] = false;
}
}
最后设定边界条件,即递归出口。
如果已经填完前8列, 就可以对结果ans加1
if(c==8){
ans++;
return;
}
整个代码如下:
#include <iostream>
using namespace std;
int ans = 0;
bool row[10], x1[20], x2[20];
bool check(int c, int i){
return !row[i] && !x1[c+i] && !x2[c-i+8];
}
void dfs(int c){
if(c==8){
ans++;
return;
}
for(int i=0; i<8; i++){
if(check(c, i)){
row[i] = x1[c+i] = x2[c-i+8] = true;
dfs(c+1);
row[i] = x1[c+i] = x2[c-i+8] = false;
}
}
}
int main() {
dfs(0);
cout<<ans<<endl;
return 0;
}