问题描述
在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。
- 定义问题的解空间
- 解的形式:( x 1 , x 2 , … , x n x_1,x_2, … , x_n x1,x2,…,xn)
- x i x_i xi的取值范围: x i x_i xi=1,2, … ,n
- 解空间是完全N叉树
- 组织解空间
- 满n叉树,树的深度为n
- 搜索解空间
- 约束条件:不同列且不处于同一正、反对角线上: ∣ i − j ∣ ≠ ∣ x i − x j ∣ |i-j|≠|x_i-x_j| ∣i−j∣=∣xi−xj∣
- 限界条件:无
- 搜索过程(以4皇后问题为例)运行结果如下, 两种解的方式:
0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 \begin{matrix} 0&1&0&0\\ 0&0&0&1\\ 1&0&0&0\\ 0&0&1&0\\ \end{matrix} 0010100000010100
0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 \begin{matrix} 0&0&1&0\\ 1&0&0&0\\ 0&0&0&1\\ 0&1&0&0\\ \end{matrix} 0100000110000010
详细代码如下:
#include <iostream>
#include <cstring>
using namespace std;
// 棋盘的大小
int n = 0;
// 棋盘,0表示有子,1表示无子
int** a = NULL;
// 解的序号
int cnt = 0;
// 约束函数 对于将要放置的点(x,y)进行判断能否放置
bool constraint(int x, int y) {
// true 能放置 false不能放置
bool flag = true;
// 不能在同一列
for (int i = 0; i < n; i++) {
if (i != x && a[i][y] == 1) {
flag = false;
}
}
if (flag == false) {
return false;
}
// 不能在从左上到右下的斜线
for (int i = 1; i < n; i++) {
int index_x1 = x - i;
int index_y1 = y - i;
int index_x2 = x + i;
int index_y2 = y + i;
if (index_x1 >= 0 && index_y1 >= 0 && a[index_x1][index_y1] == 1) {
flag = false;
break;
}
if (index_x2 < n && index_y2 < n && a[index_x2][index_y2] == 1) {
flag = false;
break;
}
}
if (flag == false) {
return false;
}
// 不能在从左下到右上的斜线
for (int i = 1; i < n; i++) {
int index_x1 = x - i;
int index_y1 = y + i;
int index_x2 = x + i;
int index_y2 = y - i;
if (index_x1 >= 0 && index_y1 < n && a[index_x1][index_y1] == 1) {
flag = false;
break;
}
if (index_x2 < n && index_y2 >= 0 && a[index_x2][index_y2] == 1) {
flag = false;
break;
}
}
if (flag == false) {
return false;
}
return true;
}
// 显示相应的棋盘信息
void display() {
cout << "*************************************************" << endl;
cout << "第" << ++cnt << "种方法" << endl;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << a[i][j] << " ";
}
cout << endl;
}
cout << "***************************************************" << endl;
}
// times代表的是当前的行号
void BackTrace(int times) {
// 递归到最后一层了,打印输出
if (times == n) {
display();
return;
}
// 遍历当前行的每一个点,查看是否满足约束函数
for (int i = 0; i < n; i++) {
if (constraint(times, i)) {
a[times][i] = 1;
BackTrace(times + 1);
a[times][i] = 0;
}
}
}
int main() {
cout << "请输入棋盘大小 : ";
cin >> n;
a = new int* [n];
// 申请空间并一开始全部置0,表示没有放子
for (int i = 0; i < n; i++) {
a[i] = new int[n];
memset(a[i], 0, sizeof(int) * n);
}
// 从第0行进行递归搜索
BackTrace(0);
// 一种解都没有,则证明无解
if (cnt == 0) {
cout << "矩阵维度为 " << n << " * " << n << "无解" << endl;
}
// 释放空间
for (int i = 0; i < n; i++) {
delete[]a[i];
}
delete[]a;
return 0;
}
验证经典的
8
8
8皇后问题,运行结果如下: