N-皇后问题的演进(附代码)
[TOC]
一、该类问题的通用回溯解法
N 皇后问题的解法是典型的回溯算法,回溯算法本质上就是穷举决策树。暴力有效。
回溯问题的解法框架:
1 | res = [] |
关于这类回溯问题如何解,推荐这篇文章回溯算法解题套路框架
二、N 皇后问题两个核心问题
N 皇后问题 有两个需要关键处理的:
- 回溯,可以直接套模版
- 合法的放置皇后,判断位置的是否合法
如何判断位置是否合法
该部分主要参考 力扣上的这篇帖子:Accepted 4ms c++ solution use backtracking and bitmask, easy understand.
如何算合法放置?
N个皇后,要求放置时不同行,不同列,不同对角线
,如果算法是遍历每行(当然也可以遍历每列,并确保每行只有一个皇后,那么只需考虑,不同列,和不同对角线)
关于对角线部分,其实只需考虑 45度方向(即左上方)135度方向(即右上方),因为递归遍历每行时,当到达某行时,未遍历的行数皆没有放置皇后。
故可以得出代码(直接放原博主的C++代码):
1 | class Solution { |
这样在判断皇后位置是否合法时,其实有很多冗余计算,不妨以空间换时间,通过数组存下位置的状态(是否可以放置皇后),原博主天才的想法:
对于 n皇后,总共有n列,45° 对角线数目:2*n-1, 对角线135°的数目也为2 * n-1。当到达[row,col]时,列号为col,则 45°对角线编号为row + col,而135°对角线编号为n-1 + col- row。 我们可以使用三个数组来指示列或对角线之前是否有王后,如果没有,我们可以将王后放在这个位置并继续。
示意图:
代码实现(原博主的C++代码):
1 | /** | | | / / / \ \ \ |
其实完全没有必要开辟三个数组,一个flag数组就够。现在,当到达[row,col]时,列的下标为col,对角线45°的下标为n + row + col,对角线135°的下标为n + 2 * n-1 + n-1 + col -行。flag 数组的大小为 n+2n-1+2n-1=5n-2
代码实现(python3):
1 | class Solution: |
但是python中修改字符串其实挺浪费时间的,完全可以存一个列号,等求出所有的排列后,再构造出棋盘分布。
代码如下:
1 | class Solution: |
17-21行代码是构造棋盘分布的
总结
- 回溯问题要学会套模板,
- python 代码最好尽可能解耦合,模块化,降低模块的耦合性。