BM59 N皇后问题¶
较难通过率 43.54%python3核心代码模式样例通过牛客 AC递归
讲解章节:DFS 深度优先搜索
一句话
逐行放皇后,用列与两条对角线的占用集合剪枝,回溯累加解的个数。
解题思路¶
这题考什么¶
要求「任意两个皇后不同行」,那就干脆一行放一个: 枚举对象从 n*n 个格子降到「第 r 行放第几列」,搜索树的深度固定是 n, 同行冲突被枚举方式本身消化掉,不必再检查。
剩下三个约束都能 O(1) 判断,关键是给每条线找一个不变量:
于是维护三个集合 cols / diag / anti,放子时把 c、r-c、r+c 记进去, 撤销时删掉。第 r 行试列 c 前先查这三个集合,命中任何一个就跳过。
r=0 . Q . . cols={1} diag={0-1=-1} anti={0+1=1}
r=1 . . . Q c=3 与已放的都不冲突 -> 继续下一行
r=2 Q . . .
r=3 . . Q . 放满 4 行 -> 解数 +1
回溯与剪枝的一般写法见 记忆化搜索与剪枝。
数据规模与复杂度¶
1 <= n <= 9,时限「其他语言 2 秒」。深度 n、每层至多 n 个分支,上界 O(n!); 三个集合的剪枝把实际展开的节点压到万级以内,n=8 有 92 种摆法、n=9 有 352 种, 最大的一档也是眨眼跑完。空间 O(n):递归深度 n,三个集合各最多 n 个元素。 不剪枝的写法(放满 n 个再回头两两验证)要枚举 n^n = 3.9e8 种放法,量级完全不同。
坑在哪¶
- 返回的是解的个数(一个整数),不是棋盘。递归里只需累加计数, 不必拼出每种摆法的字符串,省掉的正是这类题最耗时的一段。
- 两条对角线的不变量不能弄混:主对角线是 r - c、副对角线是 r + c。 两条都用 r + c 会漏判一半冲突,答案偏大。
- r - c 可能是负数。这里用集合存标识,负下标无所谓; 若改用数组标记,必须整体加偏移量 n-1,否则负下标会绕到数组尾部误判。
- 撤销要三个集合一起删,漏掉任何一个都会让后续兄弟分支误以为某条线仍被占用, 解数偏小且没有任何报错。
- n=1 的答案是 1(示例 1),不是 0——一个皇后自己不与任何皇后冲突。
样例复核¶
n=4 时,第 0 行放列 1、第 1 行只能放列 3、第 2 行只能放列 0、第 3 行只能放列 2, 得到一种摆法;镜像的那一种由第 0 行放列 2 展开而来,共 2 种,与题面描述一致。
参考实现¶
[:octicons-arrow-left-16: BM58](BM58.md) [BM60 :octicons-arrow-right-16:](BM60.md)