回溯法–N皇后问题
解决问题:
给定一个N*N的棋盘,要在棋盘上摆放N个皇后,并且满足N个皇后中任意两个皇后都不处于同一行、同一列、同一条斜线上(正斜线、反斜线)
解决步骤:
1、按行来摆放皇后
2、判断每一行的皇后是否是同一列或是否在同一斜线上
定义一个数组q[N+1]。
其中q[i]表示第i个皇后在第i行上的第q[i]列。
判断是否在同一斜线上:
|i-j| == |q[i]-q[j]| (|i行-j行|==|i列-j列|)
非递归迭代方法代码:
#include<stdio.h>
#include <math.h>
#define N 4
int q[N + 1]; //存储皇后的列号 q[i]:表示第i个皇后在第i行的第q[i]列
//判断第j个皇后是否合法
int check(int j) {
int i;
for (i = 1; i < j; i++) {
if((q[i] == q[j])||(abs(i - j) == abs(q[i] - q[j]))) //判断第j行是否有跟1-(j-1)行中的皇后同列或同斜线
return 0;
}
return 1;
}
//求解N皇后 方案
void queen() {
int i;
int answer = 0; //方案数
for (i = 1; i <= N; i++) { //初始化,暂未摆放皇后
q[i] = 0;
}
int j = 1; //表示正在摆放第j个皇后
while (j >= 1) {
q[j] = q[j] + 1; //让第j个皇后向后一列摆放
while ((q[j] <= N) && (!check(j))){ //判断第j个皇后是否合法
q[j] = q[j] + 1; //不合法就往后一个位置摆放
}
if (q[j] <= N) { //表示第j个皇后找到一个合法的位置
if (j == N) { //找到了N皇后的一组解
answer = answer + 1;
printf("方案%d:", answer);
for (i = 1; i <= N; i++) {
printf("%d ", q[i]);
}
printf("\n");
}
else {
j = j + 1; //继续摆放下一个皇后
}
}
else { //表示第j个皇后找不到一个合法的摆放位置
q[j] = 0; //还原第j个皇后的位置
j = j - 1; //回溯
}
}
}
int main() {
queen();
return 0;
}
递归方法代码:
#include<stdio.h>
#include <math.h>
#define N 4
int answer = 0; //方案数
int q[N + 1]; //存储皇后的列号 q[i]:表示第i个皇后在第i行的第q[i]列
//判断第j个皇后是否合法
int check(int j) {
int i;
for (i = 1; i < j; i++) {
if ((q[i] == q[j]) || (abs(i - j) == abs(q[i] - q[j]))) //判断第j行是否有跟1-(j-1)行中的皇后同列或同斜线
return 0;
}
return 1;
}
//求解N皇后 方案
int queen(int j) {
int i;
for (i = 1; i <= N; i++) {
q[j] = i;
if (check(j)) { //当摆放的位置为合法时
if (j == N) { //找到了N皇后的一组解
answer = answer + 1;
printf("方案%d:", answer);
for (i = 1; i <= N; i++) {
printf("%d ", q[i]);
}
printf("\n");
}
else {
queen(j + 1);
}
}
}
}
int main() {
queen(1);
return 0;
}
运行结果: