八皇后问题,是指在8X8d的棋盘上放置八个皇后,使得她们不能互相攻击,皇后的攻击范围是同行同列,或是在一条对角线上,满足上列条件的摆法一共有多少种?
这道题的一般思路是从64个格子中,挑选八个格子判断是否满足条件。这种思路简单就是通过不断的遍历枚举把所有情况表示出来。但是这样会有4.426*10^8种情况,这样做可以但是不够好。
但是这样想的思路是正确的,仔细想想,可以在上面的思路中加上一点约束:从每一列中挑选一个格子,那么就转化为从八个格子的排列组合,只有8!也就是40320种情况。可以这样想的原因是因为题目中皇后的攻击范围是同行同列同对角线,那么如果从第一列中确定了第一个皇后的位置后,剩下的7个就没必要去第一列寻找合适的位置了。下面先放上c++代码。
#include <iostream>
using namespace std;
int a[8];
int tot=0;
int n=8;
void hh(int var){
if (n==var){tot++;}
else for(int i=0;i<n;i++){
a[var]=i;
int ok=1;
for(int j=0;j<var;j++){
if (a[j]==a[var]||j+a[j]==var+a[var]||j-a[j]==var-a[var]){
ok=0;
break;
}
}
if (ok==1){
hh(var+1);
}
}
}
int main(){
int var=0;
hh(var);
cout<<tot<<endl;
return 0;
}
代码中定义的hh函数即是求解八皇后的核心部分,tot就是解的个数。
如果没写代码之前可能会觉得要用到二维数组,毕竟棋盘看作二维物品。但是代码中却只定义了a[8]。
这是因为我们可以用数组下标来表示列数,数组中存放的内容是第几列。即a[3]=4代表第三列中的第三行有一枚棋子。
我们可以先不关注函数第一行的if判断,因为从在调用hh(var)时,var=0,n=8。所以if语句在目前看来没有作用。从第一个for循环开始分析,a[var]=i,这里的用意是从第var列第i行开始枚举第一个皇后的位置,然后定义了一个ok,ok的用处稍后再说。第二个for循环就是用来判断第一个for之后添加的位置是否可以攻击前几列中已经摆放好的棋子。if (a[j]==a[var]||j+a[j]==var+a[var]||j-a[j]==var-a[var])就是判断语句,这个语句看起来很复杂,判断中总共有三个条件,第一个条件很好理解j<var,所以a[j]代表前几列的棋子位置,如果a[j]==a[var]代表在同一行重合了。后两个判断则是用来判断对角线的观察一下代码自己画个棋盘就可以想明白代码的含义。如果if条件满足了则把ok变为0,所以ok的作用就是判断a[var]是否合法。如果合法就可以通过hh(var+1)来递归。当var==n时也就说明了当前数组a已经被填满了。就是一种可行情况。而break的作用就是如果发现当前a[var]不满足条件,则停止调用下一列的递归,这种做法就是传说中的回溯。