n皇后问题的要求就是在nxn的棋盘上面所有的皇后不能相互攻击,通俗的讲就是所有的皇后既不在同一行也不在同一列,不在同一对角线。例如下图这样:
这是4皇后问题的所有解的情况,图中星号代表皇后所放位置。当然还有8皇后等等。n皇后问题是一个经典的回溯算法,为了减小代码的空间复杂度,所以这里使用尾递归来求解。递归的一个特点就是,他会记录每次求得的值,在需要用到已经计算过的值时函数可以直接调用上一次计算好的值。现在我们就来实现一个可以输出n皇后问题所有解的算法,下面的代码核心算法就是递归求解,但place函数也值得注意。
#include<iostream>
#include<cmath>
using namespace std;
int l[20];//皇后所在列数
int n;//皇后个数
void output(int n) {//输出n皇后的某个解
int i;
for (i = 1; i <= n; i++) {
cout << l[i];
}
cout << endl;
}
int place(int t,int r) {//判断第r行皇后能否放在第t列
int i=1;
while(i<r){//皇后的行数r一定要大于i
if (t == l[i] || abs(r-i) == abs(t - l[i])) {
return 0;
}
++i;
}
return 1;
}
void nqueen(int m) {//递归求解
int i;
for (i=1; i <= n; i++) {
l[m] = i;
if (place(i,m)) {
if (m == n) {
output(n);//如果最后一个皇后也放置完毕,则输出结果
}
else {
nqueen(m + 1);//否则,进行下一个皇后的放置
}
}
}
}
int main() {
cout << "请输入1~20以内的数作为皇后个数:";
cin >> n;
if (n > 20) {
cout << "输入值偏大,请重新输入:";
cin >> n;
}
nqueen(1);
system("pause");
return 0;
}
测试结果:
对上面代码解释:
t == l[i] 判断不在同一行 abs(r-i) == abs(t - l[i]) 判断不在同一对角线
在这里之所以没有判断不在同一行是因为,每一行只放一个皇后,所以自然不需要判断。