#利用回溯法解决八皇后问题
这个地方的回溯不好理解,强调一下
为什么回溯
假如现在放的是第六个皇后,其实是在check(第5个皇后)中调用了check(第6个),从第一列位置开始尝试放置皇后,直到最后一个位置都在冲突,必须修改上一个皇后的位置才能解决。
check(第6个)这一段代码就结束了,继续执行check(第5个皇后)未执行完的代码,即回溯。
又假如现在成功放置完最后一个皇后,那么最内层被调用的check结束,回到倒数第二层函数继续执行。也就是尝试将前面皇后位置后移,得到所有结果。
如何理解回溯
举一个看上去更轻松的例子。
void A(){
B();
t++();
}
void B(){
C();
i++;
}
A执行,B被调用,C被调用
C结束 ,先把B中i++执行完毕,
B结束,再将A中代码执行完毕。
递归和回溯本质上都是函数调用,自己调自己
区别是递归最后一次调用结束,回到倒数第二次调用,依次回到第一次调用;回溯是在回退过程中,再次调用下一层的函数,看代码,假如不是在调用本身
void A(){
B();
t++();
}
void B(){
C();
i++;
C();//再次调用C,八皇后中是循环调用C,直到循环结束
}
附上完整C++代码
#include <iostream>
#include <math.h>
using namespace std;
int m = 8;
int c = 0;
int queen8[8];
void print();
bool judge(int n);//判断放置第n个皇后时,有没有攻击
void check(int n);//
int main()
{
check(0);
cout << "共有" << c << "种解法" << endl;
return 0;
}
//首先是第一个皇后,将第一个皇后放在第一列,判断当前已放置皇后(还未放置,一
//定不攻击)与第一个皇后是否攻击;将第二个皇后放到1格子,判断是攻击状态,
//将第二个皇后放到2格子,判断是攻击状态,再继续放后放...直到不攻击位置。
//当放入第n个皇后,每个位置都是攻击状态时,进行回溯。
void check(int n) {
if (n == m) {
print();
return;
}
for (int i = 0; i < m; i++) {
queen8[n] = i;
if (judge(n))
check(n + 1);
}
}
void print() {
c++;
for (int i = 0; i < m; i++) {
cout << queen8[i] << " ";
}
cout << endl;
}
//判断放置第n个皇后时,有没有攻击
bool judge(int n) {
int j;
for (j = 0; j < n; j++) {
if (queen8[j] == queen8[n] || abs(queen8[j] - queen8[n]) == abs(j - n))
return false;
}
return true;
}