问题描述:
在n*n格的棋盘上放置n个皇后,其中任意的2个皇后不在同一行或同一列或是同一斜线上,即任意2个皇后不在一条直线上。
解法一递归回溯法:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef int BOOL;
#define TRUE 1
#define FALSE 0
#define N 20
void place(int x2);
void print_result();
void backtrack(int line);
void recursive_queen(int n);
static int n; // 棋盘的规模,也是皇后的个数
static int sum = 0; // n皇后问题解的个数
static int s[N]; // n元组s表示n皇后问题的解,s[i]表示皇后i放在棋盘的第i行的第s[i]列
int main() {
printf("输入n值: ");
scanf ("%d", &n);
if (n <= 0 && n > N) {
printf("n ERROR!\n");
exit(EXIT_FAILURE);
}
recursive_queen(n);
printf("%d\n", sum);
return EXIT_SUCCESS;
}
/*
** 递归回溯法求解n皇后问题
*/
void recursive_queen(int n) {
int i;
for (i = 0; i < n; i++)
s[i] = 0;
backtrack(0); // 从第0行开始摆放皇后
printf("共有%d摆放法。\n", sum);
}
/*
** 递归回溯法求解
** line表示当前正要摆放皇后的行数
*/
void backtrack(int line) {
int i;
if (line >= n){ // 已经摆放完每一行,得出解
sum++;
print_result();
} else { // 还未摆放完
for (i = 0; i < n; i++) { // 从第0列开始到第n-1列,逐一地去尝试摆放
s[line] = i;
if (place(line)) // 如果可以摆放,则摆放下一行;否则尝试下一列
backtrack(line+1);
}
}
}
/*
** 两个皇后不能在同一列上,即s中的任意两个不同的s[i], s[j]互不相同;
** 两个皇后不能在同一斜线上,即任意两个皇后连成的直线斜率不为±1,
** 即对点(x1, y1)和(x2, y2),|x1 - x2| != |y1 - y2|
*/
BOOL place(int x2) {
int x1;
for (x1 = 0; x1 < x2; x1++){
if ( (s[x1] == s[x2]) || (abs(x1 - x2) == abs(s[x1] - s[x2])) ) {
return FALSE;
}
}
return TRUE;
}
/*
** 打印皇后摆放位置的结果
*/
void print_result() {
int i, j;
printf("第%d种摆放法:\n", sum);
for (i = 0; i < n; i++ ) {
for (j = 0; j < n; j++) {
if (j == s[i])
printf("■"); // 放置皇后
else
printf("□"); // 未放置皇后
}
putchar('\n');
}
putchar('\n');
}
解法二迭代回溯法:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef int BOOL;
#define TRUE 1
#define FALSE 0
#define N 20
BOOL place(int x2);
void print_result();
void iterative_queen(int n);
static int n; // 棋盘的规模,也是皇后的个数
static int sum = 0; // n皇后问题解的个数
static int s[N]; // n元组s表示n皇后问题的解,s[i]表示皇后i放在棋盘的第i行的第s[i]列
int main() {
printf("输入n值: ");
scanf ("%d", &n);
if (n <= 0 && n > N) {
printf("n ERROR!\n");
exit(EXIT_FAILURE);
}
iterative_queen(n);
printf("%d\n", sum);
return EXIT_SUCCESS;
}
/*
** 迭代回溯法求解n皇后问题
*/
void iterative_queen(int n) {
int line = 0; // 当前正要摆放皇后的行数
s[0] = 0; // 第0列从第0行开始迭代
while (line >= 0) { // 当回溯至第-1行时,迭代结束
while ( (s[line] < n) && !place(line) ) // 寻找下一个可以放置皇后的列
s[line]++;
if (s[line] < n) { // 存在可以放置皇后的列
if (line == n - 1) { // 求得问题解
sum++;
print_result();
} else { // 还未求得问题解
line++; // 迭代下一行
s[line] = 0; // 下一行从第0列开始迭代
continue;
}
} else // 每一列都不能够放置皇后,回溯
line--;
s[line]++; // 迭代下一列
}
}
/*
** 两个皇后不能在同一列上,即s中的任意两个不同的s[i], s[j]互不相同;
** 两个皇后不能在同一斜线上,即任意两个皇后连成的直线斜率不为±1,
** 即对点(x1, y1)和(x2, y2),|x1 - x2| != |y1 - y2|
*/
BOOL place(int x2) {
int x1;
for (x1 = 0; x1 < x2; x1++){
if ( (s[x1] == s[x2]) || (abs(x1 - x2) == abs(s[x1] - s[x2])) ) {
return FALSE;
}
}
return TRUE;
}
/*
** 打印皇后摆放位置的结果
*/
void print_result() {
int i, j;
printf("第%d种摆放法:\n", sum);
for (i = 0; i < n; i++ ) {
for (j = 0; j < n; j++) {
if (j == s[i])
printf("■"); // 放置皇后
else
printf("□"); // 未放置皇后
}
putchar('\n');
}
putchar('\n');
}
结果输出:
输入n值: 6
第1种摆放法:
□■□□□□
□□□■□□
□□□□□■
■□□□□□
□□■□□□
□□□□■□
第2种摆放法:
□□■□□□
□□□□□■
□■□□□□
□□□□■□
■□□□□□
□□□■□□
第3种摆放法:
□□□■□□
■□□□□□
□□□□■□
□■□□□□
□□□□□■
□□■□□□
第4种摆放法:
□□□□■□
□□■□□□
■□□□□□
□□□□□■
□□□■□□
□■□□□□
共有4摆放法。