所谓N皇后问题,就是在一个N*N棋盘上放置N个皇后,每一个皇后所在的行,列以及它的对角线都只能有其自身,我们需要统计N个皇后时满足皇后布置的情况。
题目图解如下:
在5*5的棋盘上放置5个皇后,每个皇后所在的行,列以及它所对应的对角线都只有其自身,以下是满足皇后摆放位置的一种情况:
可以看到,每个皇后的位置都符合题目的规定,给个皇后所在的行,列以及其对角线都只有它自己
我们需要找出满足这种皇后摆放的所有解法。
但是下面的皇后的拜访就出了问题,因为第二行第五列的皇后的对角线上有其他的皇后
在一个棋盘中,我们一般将其看成二维数组,这样能够很直观的看到皇后的位置,但其实我们也可以通过一维数组来表示此二维数组
一维数组a[i],i相当于行数,a[i]的值相当于列
全局变量n定义了皇后的个数以及行数,列数
全局变量cnt统计皇后有多少种摆法
#define N 100
int a[N];//i代表行,a[i]代表列,用一维数组就足够了
int cnt;//皇后的摆法
int n;//皇后摆放的行数,皇后的数量和行数一致
我们在摆放皇后时,可以定义一个函数来表示,函数的形参为摆放皇后开始摆放在哪一行的行数
当我们摆放到最后一行(也就是棋盘的边界)时,证明当前的N皇后情况摆放完毕,那么统计皇后的摆放的计时器cnt++
row==n+1为边界,因为我们从一维数组下标为1开始摆放,不考虑一维数组下标为0的行。
void dfs(int row) {//表示第row皇后放在何处
if (row == n + 1) {
//都到达边界了,那就产生了一组解
cnt++;
return;//返回
}
}
如果此时还不是边界,也就是1-n行的位置,那么我们每一次摆放皇后的时候,
都需要判断当前(行,列)位置能否放置符合题目要求的皇后:
//从第一列遍历到最后一列
for (int i = 1; i <= n; i++) {
//调用check函数查看这一行这一列能不能放皇后
if (check(row, i)) {
a[row] = i;// 放置皇后 因为a[row]的结果充当了列数
dfs(row + 1);//放下一位置的皇后 直到row==n+1产生一组解
a[row] = 0;//移除当前位置的皇后 回溯的关键步骤,允许算法尝试在同一行的其他列放置皇后
}
}
a[row]=0这步不能省略,不然就无法得到正确的答案。
对于check函数:我们需要确定摆放皇后的行,列以及对角线的规律
因为我们是从行来摆放的,如果行数当前的列数不能摆放皇后,已经通过a[row]来移除皇后,在后面的列数重新寻找符合摆放皇后的列,因此在check函数中,我们不需要考虑判断行的摆放。
check(int x,int y){//传入摆放皇后的行数,列数
}
皇后它所在的列只能有它自己,因此:a[i]==y时,摆放的位置不符合,返回false
皇后它所在的对角线只能有它自己,而对角线有两种情况:
对于一、三象限的对角线:它们的横坐标与纵坐标相加都是相同的值,因此:i+a[i]==x+y时,摆放的位置不符合,返回false
对于二、四象限的对角线:它们的横坐标与纵坐标的差都是相同的值,因此:i-a[i]==x-y时,摆放的位置不符合,返回false
除了以上位置,其余位置都可以放置皇后,此时返回true
bool check(int x, int y) {//传进去行和列
for (int i = 1; i <= x; i++) {
if (a[i] == y) return false;
//两条对角线,一条和相等,一条差相等
if (i + a[i] == x + y) return false;
if (i - a[i] == x - y) return false;
}
return true;
}
以下是完整的代码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
//n皇后问题
//皇后在同一行,同一列,以及对角线上只能有一个
#define N 100
int a[N];//i代表行,a[i]代表列,用一维数组就足够了
int cnt;//皇后的摆法
int n;//皇后摆放的行数,皇后的数量和行数一致
//check函数用来判断当前位置能不能放置皇后
bool check(int x, int y) {//传进去行和列
for (int i = 1; i <= x; i++) {
if (a[i] == y) return false;
//两条对角线,一条和相等,一条差相等
if (i + a[i] == x + y) return false;
if (i - a[i] == x - y) return false;
}
return true;
}
void dfs(int row) {//表示第row皇后放在何处
if (row == n + 1) {
//都到达边界了,那就产生了一组解
cnt++;
return;
}
//从第一列遍历到最后一列
for (int i = 1; i <= n; i++) {
//调用check函数查看这一行这一列能不能放皇后
if (check(row, i)) {
a[row] = i;// 放置皇后 因为a[row]的结果充当了列数
dfs(row + 1);//放下一位置的皇后 直到row==n+1产生一组解
a[row] = 0;//移除当前位置的皇后 回溯的关键步骤,允许算法尝试在同一行的其他列放置皇后
}
}
}
int main() {
scanf("%d", &n);//输入几个皇后
dfs(1);//从第一行放起
printf("%d", cnt);
}
这个代码能够解决N皇后的问题,但是使用的时间却不是最优解,可以说是暴力解法,如有错误还请指正。