n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
这道题目我是根据《Python基础教程》上面的方法进行实现的,同时还参考了这位大神的blog,特此感谢
https://blog.youkuaiyun.com/lbaf1234/article/details/80397529
一般来说这类的问题都是以八皇后、或者四皇后作为典型案例进行分析。
借用一下大神的图片
用python解决八皇后
步骤: 1. 判断皇后防治的冲突问题
2. 利用递归实现所有放置方法的搜索
3. 根据题目的要求进行输出
关于皇后冲突的判定
用自然语言很容易描述八个皇后的位置制约关系,即棋盘的每一行,每一列,每一个条正斜线,每一条反斜线,都只能有1个皇后。如果用这个方法,判断新加入的皇后位置是否与已经存在的皇后位置冲突,先求出新皇后在哪一行,列,正反两条斜线上,再依次判断是否冲突。也不是不可以,不过实现起来较复杂又不简洁。
观察以下棋盘及每个位置坐标; :
- 发现以下规律:
- 在同一 ‘/’ 斜线上的位置,横纵坐标之 和 相同
-
在同一 ‘\’ 斜线上的位置,横纵坐标之 差 相同
由此可以很轻松的判断新皇后在正反两条斜线上是否与已经存在的皇后们的坐标冲突。
那么分析冲突的函数也就比较简单,容易理解了。
def conflict(self, state, pos):
y_pos = len(state)
if pos in state:
return True
for i in range(y_pos):
if y_pos - pos == i - state[i]:
return True
if y_pos + pos == i + state[i]:
return True
return False
接下来的关键部分:
由于放置方法为一层一层的放置,第一层放置完毕,直接从下一层进行放置。那么定义一个变量pos作为当前放置的纵坐标。
如果放置没有出现conflict,同时又是最后一层的放置(也就是最后依次放置皇后),那么可以直接保存这一次的放置方法。
对于不是最后一次放置,则需要仔细分析。
对于不是最后一次放置,放置的过程也就比较复杂了。需要考虑之前放置操作的影响,还需要考虑对于之后放置的影响。之前的会限制下一步可选的位置;而当前操作又会对下一次造成影响,这种影响不是当前就能发现的,而是需要深度遍历之后才能捕捉到的(脑壳疼!!)。
根据上面的分析,需要增加一个state变量记录放置的操作,每一次操作会更新state变量,然而基于当前的state变量向下搜索,不废话上代码:
def queens(self, num, state=()):
if num - 1 == len(state):
for i in range(num):
if not self.conflict(state, i):
yield (i,)
else:
for pos in range(num):
if not self.conflict(state, pos):
for result in self.queens(num, state + (pos,)):
yield (pos,) + result
中间采用了一点生成器,需要的可以自行学习。
最后按照题目的要求进行输出目标的要求,整体代码如下:
class Solution:
def conflict(self, state, pos):
nexty = len(state)
if pos in state:
return True
for i in range(nexty):
if nexty - pos == i - state[i]:
return True
if nexty + pos == i + state[i]:
return True
return False
def queens(self, num, state=()):
if num - 1 == len(state):
for i in range(num):
if not self.conflict(state, i):
yield (i,)
else:
for pos in range(num):
if not self.conflict(state, pos):
for result in self.queens(num, state + (pos,)):
yield (pos,) + result
def solveNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
"""
state = ()
result = []
final = self.queens(n, state)
for i in list(final):
temp = []
for item in i:
row = '.'*(item) + 'Q' + '.'*(n - item -1)
temp += [row]
result.append(temp)
return result