关于问题的描述:n皇后问题是
来源于国际象棋中的皇后,通常叫8皇后问题,即在N*N的棋盘上,放置N个皇后,要求每一横行,每一列,每一对角线上均只能放置一个皇后,求可能的方案及方案数。
下面对n皇后问题进行分析:
1.一下是一个8*8的棋盘,从第一行开始放皇后,第一行皇后可以任意放,但每一行的方法都会影响后面的皇后放置
2.当第一行放好之后开始放的第2,3,4,5,6,7,8;但第一行会影响第二行,第二行会影响第三行的放置,第三行会影响的四行的放置.........
3.就这样在每一行的皇后可以有8种选择,但合法的是固定的,所以当本行出错时就得返回上一行检查或从新放置,如果上一行没有位置可行时,就得继续返回....一直返回知道返回第一行时,说明第一个皇后放在第一行不合适,然后到下一个位置,直到合适为止。
4.第一行放好继续放第二行,当某一行出错时,回退到上一行,直到放好然后继续往下进行,直到放置到最后一行结束。
代码实现思路:
一:判断皇后放置位置合法性
1.采用一维数组的下标表示第n个皇后(等同于第n行的皇后),数组元素为皇后的所在列。
2.第n个皇后(第n行的皇后),a[n]为皇后所在列
3.行列关系及判断存放位置的正确性,条件1:满足不同列及(a[i] != a[k])(i为之前放置的0~i行下标,a[i]为前i放置皇后的列);条件2:满足不在同一对角线及两个皇后坐标斜率不为1或-1(|i - k| != | a[i]-a[k]|);
二:回退控制
1.每一行从第一列放置,合法时继续调用自身(放置函数进行下一行的放置),如果合法,放下一列,直到最后一列。
2.当最后一列仍不合法时,回退上一行,进行上一行的下一列放置,依次放置判断,合法时下一行,不合法再回退直到合法再放下一行直到放完为止。
代码实现:
#include<iostream> #include<cmath> #include<vector> using namespace std; class Nqueen { public: long NQueen() { cout<<"请输入皇后个数!"<<endl; cin>>n; sum = 0; a.reserve(n+1); init(); backtrack(1);//找合理方案,放置皇后 return sum;//合理方案个数 } private: bool place(int k)//放置位置合法性检验 { for(int j = 1;j<k;j++) if((abs(k-j) == abs(a[k]-a[j]))||(a[k] == a[j])) return false; return true; } void print()//打印每一行皇后放置列 { for(int i = 1;i<= n;i++) {cout<<a[i]<<" ";} cout<<endl; } void init()//初始化每行皇后放置在第0列,当然在这第0列和第0行不再棋盘范围以方便下标(行)的控制和列的控制 { for(int i = 0;i<= n;i++) a[i] = 0; } void backtrack(int t)//放置方法 { if(t>n)//当当前所要放置的行大于棋盘的行是说明,已经找到一种方法 { sum++;//方法数目加1 print();//打印放置位置 } else for(int i = 1;i<=n;i++) { a[t] = i; if(place(t))//满足时进行下一行放置,不满足时放置下下一列 backtrack(t+1); } //当到这是说明没有可放置的列说明前几行有问题,回退 } vector<int> a;//当前解 int n;//皇后个数 long sum;//求得解的可行方案数 }; int main() { Nqueen q; cout<<q.NQueen()<<endl; }