利用生成器yield 递归解决八王后问题
Posted stonenox
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用生成器yield 递归解决八王后问题相关的知识,希望对你有一定的参考价值。
八王后问题:
要在一个8*8的国际象棋棋盘里,放下8个王后,请问如何放置。
由于在国际象棋中,王后的杀戮区域是直线,和斜线,不论距离:如下图
所以要放置下8个王后,就必须把她们放在各自的杀戮区域之外。显然,每一行只能有且必须有一个王后。
构思代码:
1.棋盘
我们可以考虑,把棋盘用一个元组,
state = (pos1,pos2,pos3....pos8)
state中,元素的序号代表了棋盘的行 ; 元素的值(posn),则代表了王后在该行的位置.
state 的初始状态是(none,none,none....)
我们从第1行state[0]开始放置皇后
2.位置合法判断
判断某一行王后的位置是否正确:
如果在新的一行,例如第四行state[3] = pos3
那么我们可以用state[3] ,和之前3行 state[i] i = 0,1,2 依次对比。
1. 是否在同一列(直线杀戮区域)
如果state[3] 与 state[i] 相等,那么她们就在同一列,该位置不正确。
2. 是否在斜角上(45度杀戮区域)
如图,红色圆圈的位置,就是在斜线杀戮区域。 很容易看到,其实该点满足|X2-X1| = |Y2-Y1|
即: abs(state[3] - state[i] ) == abs(3-i)
有了这两个条件,我们可以写出判断位置是否合法的函数:
#判断在该棋盘(state)上,新的皇后如果放在nextX列,是否于老皇后冲突. def conflic(state,nextX): nextY = len(state) for i in range(nextY): if abs(nextX- state[i]) in (0,nextY-i): #如果与之前的皇后同列,或者ΔX=ΔY(45°角),则不可 return True return False
3. 递归查找王后位置
函数的返回条件:
当函数找到第8行的王后位置时,返回(yield) 该位置。
当找完了第八行所有位置,都没有新的合适的位置时,返回none空
函数的递归条件:
如果函数当前不是在第8行,并且找到了新的合适的位置,则进入新函数
函数的输入输出:
输入: 函数需要直到当前的棋盘信息,所以,需要输入
1. 棋盘的大小。
2.棋盘上已经存在的皇后 state() + 本函数找到的新皇后的合法位置 pos
注意pos是以元素的新式加入到state()的。
返回:
向上级函数返回的,是 当皇后位置,和其后的皇后递归得到的位置
即返回的是 pos_i ~~ pos_8 组成的元组。
可见,输入的state,并不用于结果的输出,结果的输出是由pos一层一层往回迭代的。
代码如下:
#num: 棋盘的尺寸(行,列都为num),也是皇后的个数, #state: 元组,序号是行,值为该行中皇后的列位置 def queen(num=8,state=()): row = len(state) #获得现在的行 for i in range(num): #对所有列位置做: if not conflic(state,i): #找出可以放的位置 if (row == num-1) : #是最后一行 yield (i,) #暂停并返回 位置(next也是从此处恢复) else : #不是最后一行 for pos in queen(num,state+(i,)): #进入递归 yield ((i,) + pos) #从递归返回了值
注意,当函数挂起后(遇到yield),重新next()时,是从最初挂起的位置,也就是说第7层queen的 地方开始恢复执行的。
if (row == num-1) : #是最后一行
yield (i,) #暂停并返回 位置(next也是从此处恢复)
当第七层没有找到合适的点时,返回none,进入上一层queen()的如下代码
for pos in queen(num,state+(i,)): #进入递归 yield ((i,) + pos) #从递归返回了值
由于该层的pos得到了none, 所以并不执行yield,而是跳到最外层for循环,执行下一个点的判断和递归。
for i in range(num): #对所有列位置做:
这样,就是先了所有点的遍历。
该函数的执行结果如下:
>>> g = queen() >>> next(g) (0, 4, 7, 5, 2, 6, 1, 3) >>> next(g) (0, 5, 7, 2, 6, 3, 1, 4) >>> next(g) (0, 6, 3, 5, 7, 1, 4, 2) >>>
我们可以执行很多次next(g),因为这个程序其实是以固定的方式,遍历了所有的可能。
总共有多少种可能呢?
>>> len(list(queen()))
92
92种
以上是关于利用生成器yield 递归解决八王后问题的主要内容,如果未能解决你的问题,请参考以下文章
Python 生成器 匿名函数 递归 模块及包的导入 正则re