从n*n个格子中,放置n个皇后
皇后是国际象棋中最强的棋子,无论是横,竖,还是斜向,都是她的控制范围
我们需要把这n个皇后放置在这正方形的棋盘中,同时要求皇后之间不会相互影响
我看了二叉树的解决方式,是使用八叉树
即从根节点开始,其子节点分别在同一列放置一个皇后,同时各不相同
第二层同理,每一个一层子节点的子节点分别在每一个空格上放置一个皇后
这样有一个深度为9的8叉树。
这时需要遍历每一种情况,也就是说8!次遍历,将每一个满足条件的棋盘状态输出出来
这无疑是非常慢的。
于是我又学习了回溯法,它的思想可以一开始就将不符合条件的棋盘状态大部分剔除
学自
void queen(int row){
if(row==n)
total++;
else
for(int col=0;col!=n;col++){
c[row]=col;
if(is_ok(row))
queen(row+1);
}
}
算法是逐行安排皇后的,其参数row为现在正执行到第几行。n是皇后数,在八皇后问题里当然就是8啦。
第2行好理解,如果程序当前能正常执行到第8行,那自然是找到了一种解法,于是八皇后问题解法数加1。
如果当前还没排到第八行,则进入else语句。遍历所有列col,将当前col存储在数组c里,然后使用is_ok()检查row行col列能不能摆皇后,若能摆皇后,则递归调用queen去安排下一列摆皇后的问题。
还不太清楚?再慢点来,刚开始的时候row=0,意思是要对第0行摆皇后了。
If判断失败,进入else,进入for循环,col初始化为0
显然,0行0列的位置一定可以摆皇后的,因为这是第一个皇后啊,后宫空荡她想怎么折腾就怎么折腾,于是is_ok(0)测试成功,递归调用queen(1)安排第1行的皇后问题。
第1行时row=1,进来if依然测试失败,进入for循环,col初始化为0。1行0列显然是不能摆皇后的,因为0行0列已经有一个圣母皇太后在那搁着了,于是is_ok()测试失败,循环什么也不做空转一圈,col变为1。1行1列依然is_ok()测试失败,一直到1行2列,发现可以摆皇后,于是继续递归queen(2)去安排第二个皇后位置。
如果在某种情况下问题无解呢?例如前面在4皇后问题中,0行0列摆皇后是无解的。假设前面递归到queen(2)时候,发现第2行没有地方可以摆皇后,那怎么办呢?要注意queen(2)的调用是在queen(1)的for循环框架内的,queen(2)若无解,则自然而然queen(1)的for循环col自加1,即将第1行的皇后从1行2列改为1行3列的位置,检查可否放皇后后继续安排下一行的皇后。如此递归,当queen(0)的col自加到7,说明第一列的皇后已经遍历了从0行1列到0行7列,此时for循环结束,程序退出。
在主函数中调用queen(0),得到正确结果,8皇后问题一共有92种解法。
#include<iostream>
#include<math.h>
using namespace std;
int n=8;
int total=0;
int *c=new int(n);
bool is_ok(int row){
for(int j=0;j!=row;j++){
if(c[row]==c[j] || row-c[row]==j-c[j] || row+c[row]==j+c[j])
return false;
}
return true;
}
void queen(int row){
if(row==n)
total++;
else
for(int col=0;col!=n;col++){
c[row]=col;
if(is_ok(row))
queen(row+1);
}
}
int main(){
queen(0);
cout<<total;
return 1;
}

本文介绍了八皇后问题的解决方案,对比了使用二叉树和回溯法的不同策略。通过回溯法,逐步安排皇后的位置,避免皇后之间的攻击,以找到所有可能的解。八皇后问题有92种不同的解决方案。
&spm=1001.2101.3001.5002&articleId=81458355&d=1&t=3&u=9d1fc72c3f894fbd99de8b64512ea206)
1018

被折叠的 条评论
为什么被折叠?



