问题描述
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。你的任务是,对于给定的N,求出有多少种合法的放置方法。
输入格式
输入中有一个正整数N≤10,表示棋盘和皇后的数量
输出格式
为一个正整数,表示对应输入行的皇后的不同放置数量。
样例输入
5
样例输出
10
思路:
从第一个点开始枚举所有可能,判断当前位置是否可以存放一个皇后,若可以则进入下一行继续枚举。我们并不知道有多少n,也就不能确定多少层循环,所以要用到dfs去搜索所有可能。
建立一个nxn的矩阵chess存储棋盘,1代表有棋子,0代表没有棋子,初始化棋盘。
从第一行第一列开始,存放一个皇后,进入第二行,判断可以存放皇后的点,继续存放,进入下一行……直到本行没有点可以放皇后或者行数大于n。
- 若本行没有点可以存放皇后,则返回上一层
- 若已到最后一层,则计数变量count++,返回上一层
不能存放棋子的条件:
任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上
当前点坐标为(x,y)
∀i,j∈[1,n],当chess[i][j]==1时
- x==i && y==j 代表当前坐标的横向或纵向上有皇后
- |x-i|==|y-j| 代表当前坐标的45°或135°方向上有皇后
以上任意一种情况都不能存放皇后
回溯时需将当前行以下所有行初始化,并将当前点的皇后拿走。
附上代码
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int chess[11][11], count = 0;//棋盘以及可能的个数
void backtracking(int N, int layers);//回溯函数
bool search(int x, int y, int N);
int main() {
int N;
cin >> N;
memset(chess, 0, sizeof(chess));//初始化棋盘
backtracking(N, 1);
cout << count;
}
void backtracking(int N, int layers) {
int x = 1;//x用来遍历layers层的每个点
if (layers > N)//若当前层数大于N就不再继续
return;
while (x <= N) {
if (x < N) {//当前行未放棋子,下面所有行必定没有棋子
for (int i = layers + 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
chess[i][j] = 0;
}
}
}
if (layers > 1 && search(layers, x, N)) {
x++;
continue;
}
chess[layers][x] = 1;//当前点放一个棋子
if (layers == N) {
count++;
x++;
continue;
}
//进入下一层
backtracking(N, layers + 1);
//从下一层回溯上来,取走当前点的皇后
chess[layers][x] = 0;
x++;
}
}
bool search(int x, int y, int N) {
for (int i = 1; i <= x; i++) {
for (int j = 1; j <= N; j++) {
if (chess[i][j] == 1 && (labs(x - i) == labs(y - j) || (i == x || j == y))) {
//|x-i| == |y-j| 即可表达该点的45°与135°上的点
return false;
}
}
}
return true;
}