n皇后问题
题目:在N*N格的格子上摆放N个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法?
分析:
①N*N个格子的棋盘可以用二维数组表示,但可用一个长度为n的一维数组,每个皇后坐标表示为 ( i , v[ i ] ) ,这样更为节省空间。
②任意两个皇后不能处于同一行、同一列或同一斜线上,则能得出每两个皇后( x1,y1 )(x2,y2)满足
(x1-x2)==(y1-y2) 且 x1 != x2 , y1 != y2
③当使用一维数组进行存放皇后坐标时,已能满足 x1 != x2,只需判断另外两种条件即可
思路:
将摆放一次皇后分为两个步骤:
1、开始放置第 t 个皇后
2、判断第 t 个皇后是否能被安全放下
当 “第 t 个皇后能被安全放下” ,则 “开始放置第 t+1 个皇后"
当 ” 第 t 个皇后不能被安全放下 “,该摆法行不通,则更换t-1皇后位置,重新判断 t-1 个皇后是否能够安全放下
不断地放置皇后,当 “开始放置n+1个皇后” 时,已经放置了n个皇后,即寻找到一种摆法。
实现:
方法一(递归回溯):
创建一个 Nqueen类 存放参数
1 class Nqueen 2 { 3 private: 4 int n; // 棋盘大小,皇后数量 5 int sum; // 摆法数量 6 vector<int>v; // 一维数组存放皇后坐标 7 public: 8 Nqueen(int x); // 构造函数,动态的调整一维数组长度 9 void queen(int t); // 开始放置第t个皇后 10 bool is_safe(int t); // 判断第t个皇后是否能被放下 11 void print(); // 输出答案 12 };
构造函数:
1 Nqueen::Nqueen(int x) 2 { 3 n = x; 4 sum = 0; 5 v.assign(x+1,0); 6 }
开始放置第t个皇后
1 void Nqueen::queen(int t) 2 { 3 if (t > n) //若要放置的皇后数量大于n时,已经放置了n个皇后,摆法加一 4 { 5 sum++; 6 } 7 else 8 { 9 for (int i = 1; i <= n; i++) //遍历该行每一个坐标 10 { 11 v[t] = i; //暂存一个坐标 12 if (is_safe(t)) //判断第 t 个皇后是否能被安全放下 13 queen(t + 1); //第t个皇后放置完毕,开始放置第t+1个皇后 14 } 15 } 16 return; 17 }
判断第 t 个皇后是否能被安全放下
1 bool Nqueen::is_safe(int t) 2 { 3 for (int i = 1; i < t; i++) 4 { 5 if (v[i] == v[t] || abs(i - t) == abs(v[i] - v[t])) 6 return false; 7 } 8 return true; 9 }
输出答案函数
1 void Nqueen::print() 2 { 3 cout << sum << endl; 4 }
主函数
1 int main() 2 { 3 int n; 4 cin >> n; 5 Nqueen q(n); 6 q.queen(1); 7 q.print(); 8 return 0; 9 }
方法二:(迭代回溯):
思想上,迭代回溯与递归回溯的思想是一致的,都是回溯法但各有优劣。
递归的方法简单易懂,但执行时需要不断地调用栈空间,占用内存大。且每一次调用函数都会出现开销。
迭代的方法不易理解,代码逻辑复杂,优点是效率高,不管深度多大在内存空间上都不会有太大的变化。
代码上,两种方法的区别在 queen()函数中 。
1 void Nqueen::queen() 2 { 3 v[1] = 0; 4 int t = 1; 5 while (t > 0) 6 { 7 v[t] += 1; //更换皇后坐标 8 while (v[t] <= n && !is_safe(t)) //判断该行是否能安全放下皇后 9 v[t]++; 10 if (v[t] <= n) //若能安全放下皇后 11 { 12 if (t == n) 13 sum++; //可行解加一 14 else 15 v[++t] = 0; // 判断下一行 16 } 17 else 18 t--; // 不能安全放下皇后,回溯判断上一个行皇后位置 19 } 20 return; 21 }
以下是在vs2019下执行的数据,方便大家校对。
1-1
2-0
3-0
4-2
5-10
6-4
7-40
8-92
9-325
10-724
11-2680
12-14200
以上是自己练题的个人笔记分享
另外我还在刷题平台上看到有耗时更低的方法无法查看,希望大家不吝赐教,分享下思路。

浙公网安备 33010602011771号