侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

N皇后问题II - 统计所有解的数量

2025-12-12 / 0 评论 / 12 阅读

题目

N皇后问题II - 统计所有解的数量

信息

  • 类型:问答
  • 难度:⭐⭐⭐

考点

回溯算法设计,剪枝优化,递归实现

快速回答

N皇后问题II要求计算在N×N棋盘上放置N个皇后,使得它们互不攻击的所有方案数。

  • 使用回溯算法逐行放置皇后,避免行冲突
  • 用三个集合分别记录列、主对角线和副对角线的占用情况
  • 主对角线用行号减列号标识,副对角线用行号加列号标识
  • 当放置到第N行时,计数加一
  • 通过剪枝避免无效搜索:放置前检查当前列和两个对角线是否已被占用
## 解析

问题描述

给定整数N,返回在N×N棋盘上放置N个皇后,使得它们不能互相攻击(任意两个皇后不在同一行、列或对角线)的所有不同解决方案的数量。

原理说明

回溯算法的核心思想是:

  1. 逐行放置皇后,避免行冲突
  2. 使用三个集合记录状态:
    • cols:已被占用的列
    • diag1:主对角线(行-列值相同)
    • diag2:副对角线(行+列值相同)
  3. 递归尝试每行的所有列位置:
    • 若当前位置安全(列和两个对角线均未被占用),放置皇后并更新状态
    • 递归处理下一行
    • 回溯:移除当前皇后并恢复状态
  4. 当成功放置第N个皇后时,计数器加一

代码示例(Python)

def totalNQueens(n: int) -> int:
    def backtrack(row, cols, diag1, diag2):
        nonlocal count
        if row == n:
            count += 1
            return

        for col in range(n):
            d1 = row - col  # 主对角线标识
            d2 = row + col  # 副对角线标识

            # 剪枝:检查冲突
            if col in cols or d1 in diag1 or d2 in diag2:
                continue

            # 放置皇后并更新状态
            cols.add(col)
            diag1.add(d1)
            diag2.add(d2)

            # 递归下一行
            backtrack(row + 1, cols, diag1, diag2)

            # 回溯:移除皇后
            cols.remove(col)
            diag1.remove(d1)
            diag2.remove(d2)

    count = 0
    backtrack(0, set(), set(), set())
    return count

最佳实践

  • 状态压缩:使用集合实现O(1)复杂度的冲突检查
  • 对角线标识:主对角线用row-col,副对角线用row+col,确保唯一性
  • 剪枝优化:在递归前进行冲突检测,避免无效递归
  • 空间优化:使用单个整数位运算替代集合(进阶技巧)

常见错误

  • 忘记回溯:递归返回后未恢复状态,导致状态污染
  • 对角线计算错误:混淆主副对角线的计算公式
  • 无效剪枝:使用二维数组遍历检查冲突,导致O(N)时间复杂度
  • 终止条件错误:未正确处理row==n的终止情况

复杂度分析

项目复杂度
时间复杂度O(N!)(最优剪枝情况下)
空间复杂度O(N)(递归栈深度+集合存储)

扩展知识

  • 位运算优化:使用整数位掩码代替集合,将空间复杂度降至O(1):
    def totalNQueens(n):
        def dfs(row, cols, diag1, diag2):
            if row == n: return 1
            count = 0
            bits = (~(cols | diag1 | diag2)) & ((1 << n) - 1)
            while bits:
                p = bits & -bits  # 获取最低位的1
                bits &= bits - 1  # 清除最低位的1
                count += dfs(row + 1, cols | p, (diag1 | p) << 1, (diag2 | p) >> 1)
            return count
        return dfs(0, 0, 0, 0)
  • 对称性优化:利用棋盘对称性减少50%计算量
  • 迭代实现:使用栈替代递归避免栈溢出
  • 并行计算:对第一行的不同列分配独立计算任务