题目
在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。
题解
递归回溯
选择了第一个皇后的位置之后,处于同行同列同斜线的位置便都无法被选择,接着放第三个皇后,同样只能放在非同行非同列非同斜线的位置,若此时没有位置能够被选择,也就意味着这种摆法是不可行的,我们需要回退到上一步!给第二个重新选择合法位置,再看是否有第三个皇后可以摆放的位置,如还是没有则再次回退至选择第二个皇后的位置,若第二个皇后也没有更多的选择则回退到第一个皇后,重新进行位置的选择。
这道题将八个皇后放在8*8棋盘,由于两两不在同一直线也不在同一对角线上,所以需要将这八个棋子放在八行上。那么我们的枚举就只需要枚举出第一行棋子在1-8列的情况,用回溯法深度优先搜索。
回溯法
- 在递归构造中,将生成和检查过程有机结合在一起
- 如果情况不满足,递归函数不再调用自身,而是返回上一级调用
- 深度优先搜索的算法结构
代码
#include<bits/stdc++.h>
using namespace std;
int size = 8;
int c[10];
void dfs(int cur);
void print_postion();
int main(){
int cur=0;
dfs(cur);
return 0;
}
void print_postion(){
printf("-----------------\n");
for(int i=0;i<size;i++){
for(int j=0; j<size; j++){
if(c[i]==j){
cout<<"|*";
}else{
cout<<"| ";
}
}
printf("|\n-----------------\n");
}
}
void dfs(int cur){
int i,j;
if(cur==size){
print_postion();
cout<<"\n";
}else{
for(i=0;i<size;i++){
c[cur] = i;
for(j=0;j<cur;j++){
if(c[cur] == c[j]||abs(j-cur)==abs(c[j]-c[cur]))
break;
}
if(j==cur) dfs(cur+1);
}
}
}
参考资料
- 《算法竞赛入门经典》第191页—八皇后问题
- https://segmentfault.com/a/1190000016775229
- https://zhuanlan.zhihu.com/p/99209213