N皇后问题是算法中很经典的一个问题,将
n
n
n 个皇后同时摆放在棋盘中,且互相不能攻击,问有多少种不同的解法。首先我们来看看题目:
从题面上看来,这道题目似乎很难入手,我们唯一的入手点就是皇后的特性,皇后就是可以攻击自己所在的行、列、左斜边和右斜边上所有的点。所以一个皇后摆放之后,就要排除这个皇后所在的行列以及两个斜边所有的点了。行和列,我们比较容易理解,那么斜边的特性是怎么样的呢?我们先来看左斜边,我们分别用字母
p
p
p 和
q
q
q 来表示行和列,那么我们可以观察到,左斜边上的点
p
p
p 和
q
q
q 的和是一个常数,也就是说在左斜边上
p
+
q
=
C
1
p+q=C_1
p+q=C1。同理在右斜边上
p
−
q
=
C
2
p-q=C_2
p−q=C2。有了这些特性,我们可以用行的深度优先遍历来进行问题的求解,代码如下:
class Solution(object):
def solveNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
"""
# 深度优先遍历的辅助函数
def _DFS(col, xy_dif, xy_sum):
p = len(col)
# 搜索终止的条件
if p == n:
result.append(col)
return None
# 遍历棋盘的列
for q in range(n):
if q not in col and p-q not in xy_dif and p+q not in xy_sum:
_DFS(col + [q], xy_dif + [p-q], xy_sum + [p+q])
result = []
_DFS([], [], [])
# 双层循环打印输出答案
return [["." * i + "Q" + "." * (n - i- 1) for i in sol] for sol in result]
第52题其实是一样的道理,只需要把返回的结果进行一下改动就行,首先看看题目:
代码和上面的一样,只需要改动返回的结果即可:
class Solution(object):
def totalNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
"""
def _DFS(col, xy_dif, xy_sum):
p = len(col)
if p == n:
result.append(col)
return None
for q in range(n):
if q not in col and p-q not in xy_dif and p+q not in xy_sum:
_DFS(col + [q], xy_dif + [p-q], xy_sum + [p+q])
result = []
_DFS([], [], [])
return len(result)
这就是N皇后问题的解法,希望能够帮助各位读者理解深度优先遍历以及递归算法,谢谢。