N皇后问题超详细解析,附带关键知识点

答题

N皇后问题要求在一个N×N的棋盘上放置N个皇后,使得它们互不攻击,即任何两个皇后都不能处于同一行、同一列或同一斜线上。

先放代码

python 复制代码
def solveNQueens(n):
    # isSafe函数用于检查在放置第n个皇后时,是否有任何冲突
    def isSafe(row, col, board):
        # 检查之前的行,对于每一个已放置的皇后
        for i in range(row):
            # 检查竖直方向、两个对角线方向是否安全
            # board[i] == col 检查同列冲突
            # board[i] - i == col - row 检查主对角线冲突
            # board[i] + i == col + row 检查副对角线冲突
            if board[i] == col or \
               board[i] - i == col - row or \
               board[i] + i == col + row:
                return False
        return True

    # backtrack是递归函数,用于尝试在棋盘的每一行放置皇后
    def backtrack(row, board):
        # 如果当前行是棋盘之外,意味着我们成功放置了所有的皇后
        if row == n:
            # 将当前板的副本添加到结果中
            result.append(board[:])
            return
        # 尝试在当前行的每一列放置皇后
        for col in range(n):
            if isSafe(row, col, board):
                # 在当前位置放置皇后
                board[row] = col
                # 递归到下一行
                backtrack(row + 1, board)
                # 回溯:移除当前行的皇后,尝试下一个位置
                board[row] = -1

    result = []  # 用于存储所有的解
    # 调用backtrack从第0行开始尝试放置皇后
    backtrack(0, [-1]*n)
    return result

# 打印解决方案的辅助函数
def printSolution(solutions):
    for solution in solutions:
        for i in solution:
            row = ["."] * len(solution)
            row[i] = "Q"
            print(" ".join(row))
        print("\n")

# 解决N=4的N皇后问题并打印解
n = 4
solutions = solveNQueens(n)
printSolution(solutions)

解题思路

  • 整体逻辑:我们从棋盘的第一行开始,尝试在每一列放置一个皇后。对于每一个位置,我们检查放置皇后后是否冲突。如果没有冲突,我们递归地在下一行进行相同的尝试。当我们放置了最后一个皇后且无冲突时,我们找到了一个解,并将其添加到解的集合中。
  • 回溯:当我们在当前行的所有列都尝试过但没有找到可行解时,我们回到上一行,改变上一行皇后的位置,然后再次尝试。这个过程会一直重复,直到我们尝试了所有可能的排列组合。
  • isSafe函数:此函数是核心,用于检查当前选定的行和列是否安全放置皇后,即检查是否有任何形式的攻击(同行、同列、对角线)。
  • backtrack函数:这是一个递归函数,负责尝试在棋盘上放置皇后并回溯。
  • 结果存储result列表用于存储所有找到的解,其中每个解是一个列表,表示每一行皇后的位置。

回溯和递归

回溯和递归是两个在算法设计和编程中常见的概念,它们在很多场景下都会一起使用,但它们指的是不同的概念。

递归 (Recursion)

递归是一种解决问题的方法,它将问题分解为更小的子问题,然后再解决这些子问题。递归方法通常包括两个主要部分:

  1. 基本情况(Base Case):这是递归调用停止的条件,不再进一步分解问题的点。
  2. 递归步骤(Recursive Step):在这一步中,函数直接或间接地调用自身,以解决更小的问题。

递归是一种非常强大的编程技术,它可以用简洁的代码解决复杂的问题,特别是那些可以自然地分解成相似子问题的问题,如树遍历、排序算法等。

回溯 (Backtracking)

回溯是一种通过探索所有可能的候选解来寻找所有解的算法策略。在探索过程中,当发现当前候选解不可能是一个有效解时,算法会丢弃该解("回溯"),回到上一步作出不同的选择。回溯算法通常用于解决组合问题、划分问题、排列问题、子集问题、棋盘问题等。

回溯算法的特点是试错,它尝试分步去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答时,它将取消上一步甚至是上几步的计算,再通过其他可能的分步解答再次尝试寻找问题的答案。

区别和联系

  • 递归是一种方法或过程,用于分解和解决问题。它是一种编程技术,不限于特定类型的问题。
  • 回溯是一种算法策略,使用试错的思想来解决问题,特别适合于搜索和约束满足问题。回溯经常使用递归来实现,通过递归进行深度优先搜索。

简而言之,递归是一种程序结构和编程技巧,而回溯是一种算法思想和解决问题的策略。在实现回溯算法时,经常使用递归作为技术手段来进行深度优先搜索。

在一个二维矩阵(如棋盘)中,主对角线和副对角线是两个重要的概念,特别是在处理像N皇后问题这样的问题时。

主对角线和副对角线

主对角线(Main Diagonal)

主对角线是从矩阵的左上角到右下角的一条线。在一个N x N的棋盘上,主对角线上的所有元素都有一个共同的特性:它们的行号和列号是相同的。也就是说,对于棋盘上的任何一个点(i, j),如果i == j,那么这个点就位于主对角线上。

css 复制代码
cssCopy code
[Q, -, -, -]
[-, Q, -, -]
[-, -, Q, -]
[-, -, -, Q]

在上面的示例中,Q标记的位置代表放置皇后的地方,它们都位于主对角线上。

副对角线(Anti-Diagonal)

副对角线是从矩阵的右上角到左下角的一条线。在副对角线上的元素有一个特性:每个元素的行号和列号之和等于一个常数。在一个N x N的棋盘上,这个常数通常是N-1(如果我们从0开始计数)。也就是说,对于棋盘上的任何一个点(i, j),如果i + j == N - 1(或者一个固定的常数,取决于矩阵的大小和起始索引),那么这个点就位于副对角线上。

css 复制代码
cssCopy code
[-, -, -, Q]
[-, -, Q, -]
[-, Q, -, -]
[Q, -, -, -]

在上面的示例中,Q标记的位置代表放置皇后的地方,它们都位于副对角线上。

在N皇后问题中的应用

在N皇后问题中,我们需要确保没有两个皇后攻击彼此。这意味着没有两个皇后可以位于同一行、同一列、主对角线或副对角线上。通过检查行号和列号的关系,我们可以判断两个皇后是否在同一对角线上:

  • 如果两个皇后的行号和列号相等(i1 == j1i2 == j2),则它们在同一主对角线上。
  • 如果两个皇后的行号和列号之和相等(i1 + j1 == i2 + j2),则它们在同一副对角线上。

理解主对角线和副对角线的概念对于解决N皇后问题至关重要,因为它们帮助我们在放置每个皇后时避免冲突。

对应到我们具体的代码:

python 复制代码
# board[i] - i == col - row 检查主对角线冲突
# board[i] + i == col + row 检查副对角线冲突

这两个条件是用来检查在N皇后问题中,一个皇后是否放置在另一个皇后的对角线上的。这里的board[i]表示第i行皇后所在的列编号,而colrow表示当前尝试放置皇后的列编号和行编号。

条件解析

  • board[i] - i == col - row 检查主对角线:

    • 这个条件用于判断两个皇后是否在主对角线上。在主对角线上的任意两点,它们的行号和列号的差是相等的。举个例子,如果一个皇后位于(2, 2),另一个皇后位于(4, 4),它们都在主对角线上,因为4-4 == 2-2。所以,如果当前尝试放置的皇后位置(row, col)与棋盘上任一已放置的皇后i满足board[i] - i == col - row,则表示它们在同一主对角线上。
  • board[i] + i == col + row 检查副对角线:

    • 这个条件用于判断两个皇后是否在副对角线上。在副对角线上的任意两点,它们的行号和列号的和是相等的。例如,如果一个皇后位于(1, 3),另一个皇后位于(2, 2),它们都在同一副对角线上,因为1+3 == 2+2。因此,如果当前尝试放置的皇后位置(row, col)与棋盘上任一已放置的皇后i满足board[i] + i == col + row,则表示它们在同一副对角线上。

为什么这样检查

这两个条件的核心原理是基于对角线的性质:在主对角线上的任意两点,行号与列号的差是恒定的;在副对角线上的任意两点,行号与列号的和是恒定的。利用这一点,我们可以轻松检查放置的皇后是否会与任何已放置的皇后冲突(即是否在同一对角线上)。这是解决N皇后问题的关键步骤之一,确保了皇后们不会相互攻击。

相关推荐
wsxqaz4 分钟前
浏览器原生控件上传PDF导致hash值不同
算法·pdf·哈希算法
NAGNIP21 分钟前
Transformer注意力机制——MHA&MQA&GQA
人工智能·算法
摘星编程24 分钟前
多模态AI Agent技术栈解析:视觉-语言-决策融合的算法原理与实践
人工智能·算法·多模态ai·视觉语言融合·ai决策算法
NAGNIP26 分钟前
一文搞懂KV-Cache
人工智能·算法
CoovallyAIHub32 分钟前
RTMPose:重新定义多人姿态估计的“实时”标准!
深度学习·算法·计算机视觉
爱喝茶的小茶1 小时前
周赛98补题
开发语言·c++·算法
小庞在加油2 小时前
《dlib库中的聚类》算法详解:从原理到实践
c++·算法·机器学习·数据挖掘·聚类
ComputerInBook2 小时前
C++ 标准模板库算法之 transform 用法
开发语言·c++·算法·transform算法
hn小菜鸡8 小时前
LeetCode 377.组合总和IV
数据结构·算法·leetcode
Deepoch8 小时前
Deepoc 大模型:无人机行业的智能变革引擎
人工智能·科技·算法·ai·动态规划·无人机