八皇后问题 OpenJ_Bailian – 2698
【回溯法思想】
参考《妙趣横生的算法》杨峰
回溯法的基本思想是:在包含问题的所有解的解空间树中,按照深度优先搜素的策略,从根结点出发深度搜索解空间树。当搜索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续搜索下去;如果该结点不包含问题的解,那就说明以该结点为根的子树一定不包含问题的最终解,因此要跳过对该结点为根的子树的系统探索,逐层向其祖先结点回溯。这个过程叫做解空间树的“剪枝”操作。
以四皇后问题为例,可以逐行放皇后,也可以逐列放皇后,我们以逐行放皇后为例。用数组Q[4][4]记录整个棋盘。每行放置皇后的位置用列下标表示,则四皇后问题可以大致描述一下。第一行可以放置的位置(列下标)是:0,1,2,3,以第一行放置在0为例,第二行可以放置在2,3,再以第二行放置在2为例,第三行无处可放,说明第二行放置在2位置导致问题最终也不会有解,那就回溯到第二行(剪枝),把2位置改为不放置皇后,继续试探第二行的3位置,再进行深搜。
【按列放置皇后的AC代码】
#include<iostream>
using namespace std;
int a[8][8]={0};
int cnt=0;
void print(){
cout<<"No. "<<++cnt<<endl;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}
//由于是按列放置的,就不需要判断右上方和右下方了
bool check(int row,int col){
for(int t=0;t<8;t++){if(a[row][t]) return false;}//判断行
for(int t=0;t<8;t++){if(a[t][col]) return false;}//判断列
for(int s=row-1,t=col-1;s>=0 && t>=0;s--,t--){if(a[s][t]) return false;}//判断左上方
for(int s=row+1,t=col-1;s<8 && t>=0;s++,t--){if(a[s][t]) return false;}//判断左下方
return true;
}
void dfs(int col){
if(col==8) {print();}
for(int row=0;row<8;row++){
if(check(row,col)){
a[row][col]=1;
dfs(col+1);
a[row][col]=0;//回溯剪枝,继续
}
}
}
int main()
{
dfs(0);
return 0;
}