隐式图回溯法之八皇后问题解答
关于隐式图解答的八皇后问题;
**问题简述:**8皇后问题:八皇后问题就是在 8*8的格子里面放入8个皇后,要求横斜都不能有数 x,y,斜 三个方向有高于1个的皇后共线。
详细的八皇后历史问题和解空间可以参阅下面的链接:
八皇后问题维基百科
下面介绍八皇后问题的解答思路,整个过程将会详细讲解。
解答在这个回溯过程中的常见疑问和一般读者在初次碰到问题的时候没有做到优化的地方。
1, 我们的目的是在
i <- 1:8对应的每一列
那么就有: 新的皇后 |
2,相用二维数组来表示也可以,但是本来行数就可以省一个维度,也节约了内存何乐而不为呢;对于生成的结果用
3,回溯是在哪一步回溯的,很显然,让访问到下一个皇后在新的一行中石佛有位置可以安放时,如果没有一个位置可以放,那么就只有返回到上一步了: 一般越靠后,回溯越多。这也是个递归的过程,在后面我将详细说明。
解释整个思路
1,初始化我们的棋盘,棋盘上的位置都没有放置皇后,
2,进行到第
若能的话,放下,将皇后个数+1;继续在下一行放皇后;
若不能放,问为什么不能放,原因有两个,*
一个是已经放满了*,就没有新的列给你放了,所以这一步就是一个小出口,可以打印出我们要的结果;
另外一个原因就是该列中得所有位置都和以前的冲突;第8个位置很明显就没位置放了,那么就只能回溯到上一步,换下上一步的位置,再往下进行,如果仍然不行,继续往回回溯;(下面给出举例图的示例)
函数的大出口就是所有的情况我们都遍历过了。
下面是程序的代码和详细的注释,不懂的地方可以反复阅读和理解。
程序代码;
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
int print(int a[]);
int check(int a[],int k);
int main(){
int a[256]={0};
int k = 1;//i表示当前正在搜索第i行的皇后位置
int t = 1;//记录打印的次数;
int n = 8;//8皇后;设置为8
while(k>=1){
a[k]++; //在下一列放置第k个皇后
while(a[k]<=n && !check(a,k))
a[k]++;//搜索下一列
if(a[k]<=n){
if(k >= n){//判断是否为最后一个放置;
cout <<"开始打印第 " << (t++) <<" 个解。"<<endl;
print(a);}
else{
k++;//不是最后一个放置,可以继续找皇后;
}
}else{
a[k]=0;//重置a[k],回溯
k--;}
}
}
int check(int a[],int k) {//已经安置了 k-1 个皇后,前面k-1个分别皇后对应的是 a[k-1] 列
for(int i=1;i<k;i++) {//遍历前面已经放置的各列行皇后
if(abs(a[i]-a[k])==abs(i-k) || a[i]==a[k])//不在一条线和对角线上;
return 0;//不匹配;当前行即第i行,设置第j列为1;
}
return 1;//新的一列可以安置;返回后,对应的a[k]值会发生变化;a[k]++;
}
int print(int a[]){//打印8皇后;
for(int i = 1;i<9;i++){
for(int j =1;j<9; j++){
if(a[i] == j){
cout<< "^ ";
}else{
cout<< "* ";
}
}
cout<<endl;
}
return 0;
}
另外给一个递归的解答;只是把继续换成了继续调用本身这个函数,回溯体现在递归遍历过程中失败后自动复位的这个过程。也比较简单,且容易理解。
八皇后问题的递归解答方法
//print(),check()同上;
int a[256] = {0};
int n = 8;
int t = 1;
void Try(int i){
for(a[i]=1;a[i]<=n;a[i]++) {
if(check(a,i)){//如果第j列不会与之前的皇后冲突
if(i<n)//如果i<n,即还没有找到八个皇后,继续递归
Try(i+1);
else { //如果找到了一组解就输出
cout <<"开始打印第 " << (t++) <<" 个解。"<<endl;
print(a);
} } } }
int main(void){
Try(1);
return 0;
}
上面分写的过程,逻辑结构完全跟上面的回溯原理相同,不加赘述,也就是输入隐式图求解盲目求解的深度搜索。
隐式图回溯法只八皇后问题