如何实现Python高效n皇后问题求解算法?适配n≥20及更大场景
高效求解N皇后问题:Python实现与优化方案
一、核心优化逻辑
你之前用排列校验的方法,本质是生成所有可能的皇后列位置组合再逐一验证,时间复杂度为O(n! * n),n≥20时n!已是天文数字,完全不可行。
优化核心为回溯+剪枝+位运算:
- 回溯:逐行放置皇后,每放一行就记录当前约束条件,避免后续无效尝试
- 剪枝:放置皇后前直接排除会与已放皇后冲突的位置,从根源上不生成无效路径
- 位运算:用整数二进制位表示列、对角线的占用状态,位操作比数组/集合操作快数个数量级,且Python支持任意精度整数,无溢出顾虑
二、位运算优化的回溯实现
统计所有解的数量
如果仅需统计解的总数,这个实现效率极高:
def count_n_queens(n): def backtrack(cols, pie, na): # cols: 已占用列(二进制位为1表示被占用) # pie: 已占用主对角线(左上→右下) # na: 已占用副对角线(右上→左下) row = bin(cols).count('1') # 当前处理的行号(已放皇后数量) if row == n: return 1 # 计算当前行可放置皇后的位置:排除所有已约束的位 available = ((1 << n) - 1) & (~(cols | pie | na)) count = 0 while available: # 取出最右侧的1(选中一个可放置位置) pos = available & -available available ^= pos # 标记该位置已被选择 # 递归处理下一行,更新约束条件 count += backtrack(cols | pos, (pie | pos) << 1, (na | pos) >> 1) return count return backtrack(0, 0, 0)
生成所有可行解的具体棋盘
如果需要输出所有解的棋盘格式,可调整为:
def solve_n_queens(n): solutions = [] def backtrack(row, cols, pie, na, path): if row == n: # 转换为棋盘字符串格式 board = ['.'*i + 'Q' + '.'*(n-i-1) for i in path] solutions.append(board) return available = ((1 << n) - 1) & (~(cols | pie | na)) while available: pos = available & -available available ^= pos col = bin(pos).count('1') - 1 # 计算当前位置对应的列号 backtrack(row+1, cols | pos, (pie | pos) << 1, (na | pos) >> 1, path + [col]) backtrack(0, 0, 0, 0, []) return solutions
三、高效性细节说明
- 剪枝效率:每一步仅处理当前行的可行位置,不会生成任何已冲突的路径,比如n=20时,实际递归次数远小于20!,大部分无效路径在早期就被剪掉。
- 位运算速度:Python的位操作是底层实现,比用列表、集合记录约束条件快很多,判断可用位置、更新约束均为单步位运算,无循环开销。
- 递归栈安全:递归深度等于n,Python默认递归深度限制为1000,因此n≤1000时都不会栈溢出,完全覆盖n≥20甚至n=100的场景。
四、处理n=100这类超大值的场景
统计解的数量
n=100的解数量是一个超100位的数,上述统计解数量的算法可以快速计算结果(但仅为数字,无实际枚举意义)。
求单个可行解
无需遍历所有路径,找到第一个可行解就返回,效率更高:
def find_one_n_queen(n): def backtrack(row, cols, pie, na, path): if row == n: return path available = ((1 << n) - 1) & (~(cols | pie | na)) while available: pos = available & -available available ^= pos col = bin(pos).count('1') - 1 res = backtrack(row+1, cols | pos, (pie | pos) << 1, (na | pos) >> 1, path + [col]) if res: return res return None path = backtrack(0, 0, 0, 0, []) if path: return ['.'*i + 'Q' + '.'*(n-i-1) for i in path] return None
构造法生成可行解
对于n≥4的场景,可直接用构造法O(n)生成可行解,无需递归:
- 若n为偶数且不是6k+2:皇后放在(2,4,6,...,n,1,3,5,...,n-1)列
- 若n为偶数且是6k+2:皇后放在(1,3,5,...,n-1,2,4,6,...,n)列
- 若n为奇数:先按偶数方法处理n-1行,最后一行放在中间列
内容的提问来源于stack exchange,提问作者user21429639
相关产品推荐
相关产品推荐

