回溯算法之N皇后问题详细解读(附带Java代码解读)

N 皇后问题回顾

N 皇后问题的目标是将 N 个皇后放置在 N×N 的国际象棋棋盘上,确保没有两个皇后能相互攻击。皇后的攻击方式是横向、纵向以及对角线。也就是说,在棋盘上,任意两个皇后不能处于相同的行、相同的列或同一条对角线上。

回溯算法的步骤详细说明

回溯算法是一种通过递归搜索所有可能解的算法,尤其适合解决排列组合和满足条件的搜索问题。在 N 皇后问题中,我们从第一行开始放置皇后,并尝试在每一行放置一个皇后,直到所有皇后都放置完毕(即达到了 N 行)。如果当前行不能合法放置皇后,我们回溯到上一行并尝试其他列的位置。

核心思想
  1. 逐行放置皇后:从第 1 行开始,依次为每一行放置一个皇后。每一行都会尝试将皇后放置在不同的列中。
  2. 合法性检查:每放置一个皇后时,必须检查其是否与之前已经放置的皇后发生冲突。具体来说,不能和其他皇后处于同一列或同一对角线上。
  3. 回溯:如果在某一行找不到合适的列来放置皇后,则说明当前的部分解不合法,需要“回溯”到上一行,尝试改变上一行的皇后位置,直到找到新的可能解。
  4. 递归终止条件:当皇后成功放置到所有 N 行时,表示找到一个完整的解。此时,将该解保存下来,并继续搜索其他可能的解。

详细 Java 实现

import java.util.ArrayList;
import java.util.List;

public class NQueens {

    // 主方法,解决 N 皇后问题
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> solutions = new ArrayList<>(); // 用于存储所有的解决方案
        int[] queens = new int[n];  // 用于记录每一行皇后放置的列索引
        for (int i = 0; i < n; i++) {
            queens[i] = -1; // 初始化时,所有行的皇后均未放置,设为 -1
        }
        backtrack(solutions, queens, n, 0); // 从第 0 行开始递归放置皇后
        return solutions;
    }

    // 回溯方法,逐行尝试放置皇后
    private void backtrack(List<List<String>> solutions, int[] queens, int n, int row) {
        // 当 row 等于 n 时,说明已经成功将 n 个皇后放置在 n 行,找到一个解
        if (row == n) {
            solutions.add(generateBoard(queens, n)); // 将解转换成棋盘形式并加入 solutions
            return;
        }

        // 尝试将皇后放置在当前行 row 的每一个列位置 col
        for (int col = 0; col < n; col++) {
            // 检查将皇后放置在 row 行 col 列是否合法
            if (isValid(queens, row, col)) {
                // 如果合法,将皇后放置在该位置
                queens[row] = col;
                // 递归尝试下一行的皇后放置
                backtrack(solutions, queens, n, row + 1);
                // 回溯:撤销当前行皇后的放置,尝试其他列
                queens[row] = -1;
            }
        }
    }

    // 判断在 row 行 col 列放置皇后是否合法
    private boolean isValid(int[] queens, int row, int col) {
        for (int i = 0; i < row; i++) {
            // 1. 检查列冲突:若当前皇后和之前某一行的皇后处于同一列,则冲突
            if (queens[i] == col) {
                return false;
            }
            // 2. 检查对角线冲突:通过 |row - i| 和 |col

代码详细解读

1. solveNQueens 方法
  • 功能:这是解决 N 皇后问题的主方法,首先初始化一个大小为 N 的 queens 数组,用来存储每行皇后的位置。然后调用 backtrack 方法开始回溯搜索。
  • 变量说明
    • solutions:存储所有找到的解决方案,形式为棋盘的字符串表示。
    • queens:用于存储当前棋盘状态,queens[i] 表示第 i 行皇后所处的列位置,初始化为 -1 表示未放置。
  • 递归开始:从第 0 行开始递归调用 backtrack
2. backtrack 方法
  • 功能:递归地尝试为每一行放置皇后。通过检查是否能够在某列放置皇后来判断继续递归,直到找到合法解。
  • 递归终止条件:当 row == n 时,表示所有行都成功放置皇后,此时将该解添加到 solutions 中。
  • 回溯思想
    • 在某一行的每一列中尝试放置皇后。
    • 如果找到合法位置,递归进入下一行。
    • 如果当前行没有合适位置,则回溯到上一行,继续尝试其他列。
3. isValid 方法
  • 功能:用于判断在某一行的某一列放置皇后是否合法。
  • 合法性检查
    • 同列冲突:检查当前列是否已经有其他皇后占据。
    • 对角线冲突:通过检查两皇后行号和列号的差的绝对值是否相等,判断是否在同一对角线上。
4. generateBoard 方法
  • 功能:将 queens 数组中的解转换成棋盘的字符串形式,便于输出和展示。
  • 棋盘生成:对于每一行,根据 queens[i] 的值生成一行字符串,'Q' 表示皇后,'.' 表示空位。
5. 测试部分
  • 功能:解决 4 皇后问题,并输出所有的可能解。可以通过修改 n 的值来解决不同大小的 N 皇后问题。

输出示例(4 皇后问题)

.Q..
...Q
Q...
..Q.

..Q.
Q...
...Q
.Q..

这个结果展示了 4 皇后问题的两种有效解。每行的 Q 表示皇后,. 表示空位。每种解中,皇后彼此之间没有相互攻击。

时间复杂度分析

由于 N 皇后问题的解空间是 N 的阶乘 (N!) 级别,每一行最多有 N 种选择,因此时间复杂度大约为 O(N!)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值