八皇后问题是用回溯法和DFS解决的经典问题,难点在于如何判断所放的皇后是否在同一行列或是对角线上,本文就简单的介绍一下自己的思路,也算是对之前所学的知识做一个简单的总结;
- 维护皇后放入位置的数组。第一个数组是一个皇后所放置的行列位置,用一位数组即可表示,下标是行数,下标所对应的值是列数,每次递归就是往第index行的某一列放入皇后。用一维数组就不需要判断是否在同一行。
- 维护所放入列的数组。上面的一维数组只保证了是否同一行的条件,所以我们需要用一个一维数组记录哪一列放有元素,每次递归的过程中,就判断该列之前是否有放入过皇后。这样,通过维护两个数组就解决了两个皇后是否在同一行列的问题。
- 用abs(j,index)==abs(mat[j],i)来判断是否在同一对角线。首先我们要明白,如果在同一对角线,那么两个皇后的各自行列相减的值是一样的。用abs()函数返回差的绝对值。
下面就是用代码实现:
#include<cstdio>
const int maxn = 8;
int mat[maxn+1]={0};// 记录插入棋子的位置
int vis[maxn+1] = {0};// 判断插入的列是否重复
int cnt=0;
int abs(int a,int b){
return a>b?a-b:b-a;
}
void bfs(int index){// 记录的是mat的下标
if(index == maxn+1){// 说明全部插入结束,得到正确的结果
cnt++;
return;
}
for(int i=1;i<maxn+1;i++){// 开始往第index行第i列插入
if(!vis[i]){// i列之前没被插入过棋子
int flag = 1;// 判断这个位置是否可以插入的标记
for(int j=1;j<index;j++){
if(abs(j,index)==abs(mat[j],i)){//判断是否在同一对角线
flag = 0;break;
}
}
if(flag){// 如果可以,则进入下一步的递归
mat[index] = i;
vis[i] = 1;
bfs(index+1);
vis[i] = 0;
}
}
}
return;
}
int main(){
bfs(1);
printf("%d",cnt);
return 0;
}