python八皇后问题递归算法_八皇后问题--递归回溯算法(Python实现)

前两天做牛客的时候遇到了一个字符串的全排列问题。顺便回顾一下八皇后问题。(后附Python代码)

如何解决八皇后问题?

所谓递归回溯,本质上是一种枚举法。这种方法从棋盘的第一行开始尝试摆放第一个皇后,摆放成功后,递归一层,再遵循规则在棋盘第二行来摆放第二个皇后。如果当前位置无法摆放,则向右移动一格再次尝试,如果摆放成功,则继续递归一层,摆放第三个皇后……

如果某一层看遍了所有格子,都无法成功摆放,则回溯到上一个皇后,让上一个皇后右移一格,再进行递归。如果八个皇后都摆放完毕且符合规则,那么就得到了其中一种正确的解法。

解决八皇后问题,可以分为两个层面:

1.找出第一种正确摆放方式,也就是深度优先遍历。

2.找出全部的正确摆放方式,也就是广度优先遍历。

研究代码实现过程中,要解决以下几个问题:

1.国际象棋的棋盘如何表示?

很简单,用一个长度是8的二维数组来表示即可。

2.如何判断皇后的落点是否合规?

定义一个conflict方法,传入新皇后的落点,通过纵向和斜向是否存在其他皇后来判断是否合规。

3.如何进行递归回溯?

递归回溯是本算法的核心,代码逻辑有些复杂

4.如何输出结果?

这个问题很简单,直接遍历二维数组并输出就可以。

5.如何把这些方法串起来?

在main函数里分三步来调用:

第一步:初始化

第二步:递归摆放皇后

第三步:最后输出结果。

#coding=UTF-8

import random

#冲突检查,在定义state时,采用state来标志每个皇后的位置,其中索引用来表示横坐标,基对应的值表示纵坐标,例如: state[0]=3,表示该皇后位于第1行的第4列上

def conflict(state, nextX):

nextY = len(state)

for i in range(nextY):

#如果下一个皇后的位置与当前的皇后位置相邻(包括上下,左右)或在同一对角线上,则说明有冲突,需要重新摆放

if abs(state[i]-nextX) in (0, nextY-i):

# 表示如果下一个皇后和正在考虑的前一个皇后的水平距离为0或者垂直距离相等,就返回TRUE,否则返回False

return True

return False

#采用生成器的方式来产生每一个皇后的位置,并用递归来实现下一个皇后的位置。

def queens(num, state=()):

for pos in range(num):

if not conflict(state, pos):

#产生当前皇后的位置信息

#如果只剩一个皇后没有放置

if len(state) == num-1:

yield (pos, )

#否则,把当前皇后的位置信息,添加到状态列表里,并传递给下一皇后。

#程序要从前面的皇后得到包含位置信息的元组(元组不可更改)

#并要为后面的皇后提供当前皇后的每一种合法的位置信息

#所以把当前皇后的位置信息,添加到状态列表里,并传递给下一皇后。

else:

for result in queens(num, state+(pos,)):

yield (pos, ) + result

#为了直观表现棋盘,用X表示每个皇后的位置

def prettyprint(solution):

def line(pos, length=len(solution)):

return '. ' * (pos) + 'X ' + '. '*(length-pos-1)

for pos in solution:

print line(pos)

for item in queens(8):

print item

if __name__ == "__main__":

prettyprint(random.choice(list(queens(8))))

length = len(queens(8))        #92种

for item in queens(8):

print item                        #输出每一种表示

输出如下一种结果:

参考资料:1.书圈 的一个漫画 “什么是八皇后问题”点击打开链接

2.[挪]Python基础教程9.9节八皇后问题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值