问题描述:在n×n格的棋盘上放置彼此不受攻击的n个皇后。即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
思路:每个皇后都是放在单独的一行,因此同行就不用判断了。用一个数组记录每个皇后可能的列位置,比如Col[0]表示皇后0所在的列号,0到 n-1 之间的值。对于每一种排列,检查是否有在同一列或者同一对角线的两个皇后。产生全排列的算法可以参考字符串的排列。
这种方法很简单,但是效率太低了。可以改进一下,采用回溯的思想。首先考虑皇后0所在的列号,取0到7的一个。然后考虑皇后1,检查每一个可能的列号,如果与皇后0没有冲突,那么考虑皇后2;如果与皇后0有冲突,那么直接返回,继续考虑已经没有意义。
参考代码:NQueenProblem(8)计算8后问题
- //函数功能 : 检查皇后cur的摆法
- //函数参数 : n为皇后数,cur为当前检查的皇后,col为皇后的列位置,sum为找到的摆法
- //返回值 : 无
- void Queen(int n, int cur, int *col, int *sum)
- {
- if(cur == n) //找到一种摆法
- {
- for(int i = 0; i < n; i++)
- cout<<col[i]<<' ';
- cout<<endl;
- (*sum)++; //摆法加1
- return;
- }
- int i, j;
- for(i = 0; i < n; i++) //考虑每一个可能的列号
- {
- //检查当前考虑的皇后是不是可以放在位置i
- for(j = 0; j < cur; j++)
- {
- if(abs(j-cur) == abs(col[j]-i) || col[j] == i) //与之前的皇后有冲突,不用考虑下一个皇后了
- break;
- }
- if(j == cur)
- {
- col[cur] = i; //可以放在这个位置
- Queen(n, cur+1, col, sum); //考虑下一个皇后
- }
- }
- }
- //函数功能 : n皇后的摆法
- //函数参数 : n为皇后数
- //返回值 : 摆法的数量
- int NQueenProblem(int n)
- {
- int *col = new int[n];
- int sum = 0;
- Queen(n, 0, col, &sum); //调用核心函数
- delete [] col;
- col = NULL;
- return sum;
- }