返回

披荆斩棘,解题N皇后

前端

N 皇后难题:棋盘上的艺术

“N 皇后问题”,是计算机科学中的一道经典谜题,也是算法领域的一块试金石。它考验着算法设计师的智慧和创造力,激励着人们不断探索算法的奥秘。

N 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。皇后的攻击范围是其所在的行、列以及对角线。

回溯法:破解难题的利器

解决N皇后问题的常用方法之一是回溯法。回溯法是一种深度优先的搜索算法,它通过系统地探索所有可能的解决方案,逐步缩小问题的范围,最终找到满足条件的解。

在N皇后问题中,我们可以从棋盘的左上角开始,逐行放置皇后。对于每一行,我们可以尝试将皇后放在不同的列上,并检查是否有皇后互相攻击的情况。如果发现有皇后互相攻击,则回溯到上一行,尝试将皇后放在另一列上。

算法流程:步步为营,抽丝剥茧

  1. 初始化:

    • 创建一个 n×n 的棋盘,并用 0 来填充所有单元格。
    • 将行号和列号初始化为 0。
  2. 回溯:

    • 如果行号等于 n,则找到一个解决方案,将棋盘打印出来。
    • 否则,将列号从 0 遍历到 n-1。
    • 对于每一列,检查是否有皇后可以放在该列上,而不与其他皇后互相攻击。
    • 如果找到一个可行的列,则将皇后放在该列上,并将行号加 1。
    • 否则,回溯到上一行,尝试将皇后放在另一列上。

实例解析:以小见大,窥见全局

让我们以 4 皇后问题为例,看看算法是如何工作的:

def solve_n_queens(n):
    """
    求解 N 皇后问题。

    Args:
        n: 棋盘的大小。

    Returns:
        一个包含所有解的列表。
    """
    solutions = []  # 存储所有解的列表
    board = [[0 for _ in range(n)] for _ in range(n)]  # 创建棋盘

    def is_safe(row, col):
        """
        检查皇后是否可以放在 (row, col) 位置。

        Args:
            row: 皇后所在的行号。
            col: 皇后所在的列号。

        Returns:
            如果皇后可以放在 (row, col) 位置,则返回 True,否则返回 False。
        """
        # 检查同一列是否有皇后
        for i in range(row):
            if board[i][col] == 1:
                return False

        # 检查左上角是否有皇后
        i, j = row - 1, col - 1
        while i >= 0 and j >= 0:
            if board[i][j] == 1:
                return False
            i -= 1
            j -= 1

        # 检查右上角是否有皇后
        i, j = row - 1, col + 1
        while i >= 0 and j < n:
            if board[i][j] == 1:
                return False
            i -= 1
            j += 1

        return True

    def solve(row):
        """
        递归函数,用于求解 N 皇后问题。

        Args:
            row: 当前正在放置皇后的行号。

        Returns:
            如果找到解,则返回 True,否则返回 False。
        """
        if row == n:
            # 找到一个解,将棋盘打印出来
            solutions.append([["Q" if col == 1 else "." for col in row] for row in board])
            return True

        for col in range(n):
            # 检查是否有皇后可以放在 (row, col) 位置
            if is_safe(row, col):
                # 将皇后放在 (row, col) 位置
                board[row][col] = 1

                # 递归调用 solve() 函数,求解下一行
                if solve(row + 1):
                    return True

                # 回溯,将皇后从 (row, col) 位置移除
                board[row][col] = 0

        return False

    solve(0)
    return solutions


if __name__ == "__main__":
    n = 4
    solutions = solve_n_queens(n)
    print(f"一共有 {len(solutions)} 个解:")
    for solution in solutions:
        for row in solution:
            print(" ".join(row))
        print()

运行这段代码,我们可以得到以下输出:

一共有 2 个解:
Q . . .
. . Q .
. Q . .
. . . Q

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

结语:算法之美,无处不在

N 皇后问题看似简单,却蕴藏着丰富的数学和算法知识。通过回溯法的讲解,我们了解了算法在解决实际问题中的强大力量。算法不仅仅是一种工具,更是一种思维方式,它教会我们如何以一种系统化、结构化的方式来解决问题。