写在前面:
刚刚在数据结构与算法面试题上面看到了有关这个“N皇后”的东东,想着来学学看看。
什么是N皇后问题?
题目如下:
在n*n的方格棋盘上,放置n个皇后,要求每个皇后不同行、不同列、不同对角线。
回溯思路:
- 从第0行开始,逐行放置皇后。
- 对于当前行,尝试放置在每一列。
- 每放置一个皇后,都要检查当前位置是否与之前放置的皇后位置冲突:
- 同列冲突:检查当前列是否已经有皇后。
- 对角线冲突:检查当前位置是否与之前皇后的对角线有冲突。(这两条是区别于深搜的根本因素)
- 如果找到一个安全的位置放置皇后,则递归地尝试下一行。
- 如果当前位置无法放置皇后或者递归过程中无法找到解决方案,则回溯到上一步,尝试下一个列位置。
这题目,理解起来倒不是很难,递归回溯问题(尝试一条路(放置皇后),如果遇到困难(即存在冲突),则返回到上一个状态(就是回溯啦),尝试另一种可能性,直到找到解决方案或者所有可能性都被排除),so???直接上代码吧!!!
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int **board; // 棋盘
int N; // 棋盘大小
// 打印棋盘
void printBoard() {
int i, j;
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
printf("%c ", board[i][j] ? 'Q' : '.');
}
printf("\n");
}
printf("\n");
}
// 检查在board[row][col]位置放置皇后是否符合规则
bool isSafe(int row, int col) {
int i, j;
// 检查列是否有皇后冲突
for (i = 0; i < row; i++) {
if (board[i][col])
return false;
}
// 检查左上对角线是否有皇后冲突
for (i = row, j = col; i >= 0 && j >= 0; i--, j--) {
if (board[i][j])
return false;
}
// 检查右上对角线是否有皇后冲突
for (i = row, j = col; i >= 0 && j < N; i--, j++) {
if (board[i][j])
return false;
}
return true;
}
// 递归解决N皇后问题
bool solveNQueens(int row) {
// 如果已经成功放置了最后一行的皇后,打印棋盘并返回true
if (row == N) {
printBoard();
return true;
}
bool res = false;
int col;
// 尝试当前行的每一列
for (col = 0; col < N; col++) {
// 如果当前位置可以放置皇后
if (isSafe(row, col)) {
board[row][col] = 1; // 放置皇后
// 递归尝试放置下一行的皇后
res = solveNQueens(row + 1) || res;
board[row][col] = 0; // 回溯,撤销放置的皇后
}
}
return res;
}
// 主函数,调用求解函数
int main() {
int i, j;
// 输入棋盘大小
printf("Enter the size of the chessboard (N): ");
scanf("%d", &N);
if (N <= 0) {
printf("N must be a positive integer.\n");
return 1;
}
// 动态分配棋盘内存
board = (int **)malloc(N * sizeof(int *));
if (board == NULL) {
printf("Memory allocation failed.\n");
return 1;
}
for (i = 0; i < N; i++) {
board[i] = (int *)calloc(N, sizeof(int));
if (board[i] == NULL) {
printf("Memory allocation failed.\n");
return 1;
}
}
solveNQueens(0); // 从第0行开始放置皇后
// 释放棋盘内存
for (i = 0; i < N; i++) {
free(board[i]);
}
free(board);
return 0;
}