回溯算法经典问题:N皇后(简单易读,详细注释,一文看懂)

回溯法是一种用于解决组合问题的算法策略,特别适合那些可以通过逐步构造解的方式解决的问题。它的核心思想是在搜索解的过程中,逐步构建解的候选方案,并在发现某个候选方案无法成为有效解时,及时“回退”并尝试其他可能的方案。

回溯法的基本思想

  1. 逐步构建解:从一个初始解出发,逐步增加元素,构建可能的解。
  2. 剪枝:在构建过程中,检查当前构建的解是否符合问题的约束条件。如果不符合,就停止继续深入,直接回退到上一步。
  3. 全局解:当构建出一个完整的解时,将其记录下来。如果需要所有可能的解,则继续搜索

回溯法的时间复杂度

回溯法的时间复杂度通常与问题的规模和可选项的数量有关。由于它可能需要遍历所有的可能解,最坏情况下的时间复杂度可以是指数级的,例如O(n!)或O(2^n),但通过剪枝可以大幅降低实际的计算时间。

引入问题:N皇后问题(以8个皇后为例)

  • 问题描述:在8×8的棋盘上放置8个皇后,使得任意两个皇后都不能相互攻击。即同一行、同一列和同一斜线不能有两个皇后。
  • 解决思路:使用回溯法逐行放置皇后,每放置一个皇后时,检查是否与已放置的皇后冲突,如果不冲突则继续放置下一个皇后;如果出现冲突,则回退到上一个皇后,尝试在其他位置放置。

直接看代码:

#include <stdio.h>
#include <stdbool.h>

#define N 8  // 定义棋盘的大小,N为皇后的数量

// 函数声明
void solveNQueens(int board[N][N], int row);
bool isSafe(int board[N][N], int row, int col);
void printSolution(int board[N][N]);

// 主函数
int main() {
    int board[N][N] = {0};  // 初始化棋盘,0表示空位,1表示放置皇后

    // 开始解决N皇后问题
    solveNQueens(board, 0);

    return 0;
}

// 解决N皇后问题的函数
void solveNQueens(int board[N][N], int row) {
    // 如果所有的皇后都被放置了,打印解决方案
    if (row == N) {
        printSolution(board);
        return;
    }

    // 遍历当前行的每一列
    for (int col = 0; col < N; col++) {
        // 检查当前列和对角线是否安全
        if (isSafe(board, row, col)) {
            board[row][col] = 1;  // 放置皇后

            // 递归调用,尝试放置下一个皇后
            solveNQueens(board, row + 1);

            // 回溯,移除皇后,尝试下一个列位置
            board[row][col] = 0;
        }
    }
}

// 检查当前位置是否安全的函数
bool isSafe(int board[N][N], int row, int col) {
    // 检查当前列是否有其他皇后
    for (int i = 0; i < row; i++) {
        if (board[i][col] == 1) {
            return false;  // 列冲突
        }
    }

    // 检查主对角线(左上到右下)是否有其他皇后
    for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {
        if (board[i][j] == 1) {
            return false;  // 主对角线冲突
        }
    }

    // 检查副对角线(右上到左下)是否有其他皇后
    for (int i = row, j = col; i >= 0 && j < N; i--, j++) {
        if (board[i][j] == 1) {
            return false;  // 副对角线冲突
        }
    }

    return true;  // 当前位置安全
}

// 打印棋盘的解决方案
void printSolution(int board[N][N]) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            printf(" %d ", board[i][j]);  // 打印棋盘上每个位置的值
        }
        printf("\n");
    }
    printf("\n");  // 打印解决方案之间的分隔
}

以上是我对回溯法的理解,感谢大家的阅读,才疏学浅,不足之处还望大家指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值