八皇后问题(英文:Eight queens),是由国际象棋棋手马克斯·贝瑟尔于1848年提出的问题,是回溯算法的典型案例。
问题表述为:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。计算机发明后,有多种计算机语言可以编程解决此问题。
思路解析:
首先我们从八皇后的背景当中,可以看到任意两个皇后不可以同一列、行、对角线上面,对于这三行的处理,我们可以采用下列方式
一:对于行的限制,我们只需要在每一行都只放一个皇后就可以了,因为他是n*n的
二:对于列的限制,我们可以在每一次要放皇后的时候,遍历之前放过的每个皇后,判断这一列的上面有没有皇后
三:对于对角线的限制,我么会发现对角线任意两点,他们的斜率都是1or-1,所以我们可以直接遍历之前放过的皇后和现在要放的皇后判断他们的斜率会不会满足
就像n==3 得到情况就是无解
OK,现在我们已经知道怎么判断这个位置的皇后合不合法了,那么我们就可以开始尝试写代码了,首先对于这题,我们可以不需要开二维数组,因为每一行它只能放一个(对应序列0-7),所以我们可以开一个一维数组x[n],让 x[0],x[1]`````x[n-1]来对应存储每一个皇后对应的列
#include<bits/stdc++.h>
using namespace std;
bool panduan(int x[],int i){
for(int j = 0;j<i;j++){
if(x[j]==x[i]||abs(x[i]-x[j])==abs(i-j))
return false;//位置不合法,返回false
}
return 1;
}
void Queen(int x[],int n){
fill(x,x+n,-1);
for(int i = 0;i<n;){
x[i]++;//开始放皇后
while(x[i]<n&&!panduan(x,i))
x[i]++;//不合法,让皇后往后推一列
if(x[i]==n) {//回溯,当前第i位皇后在这一行没有位置可以放,只能回溯之前的皇后
x[i]=-1;
i--;
}
else if(i<n-1) i++;//继续下一行
else {//i==n的情况,有满足的情况,打印
for(int j = 0;j<n;j++){
cout<<x[j]+1<<" ";
}
cout<<endl;
return;
}
}
}
int main()
{
int n;
cin>>n;
int x[n];
Queen(x,n);
}
这样就可以得到八皇后问题的其中一个解
做题感悟:通过这题,我也更加的理解了回溯法在题目当中的巧妙运用,花了不少时间来理解这一题,如果有任何不足的地方,欢迎大家指出