python3 回溯法解决八皇后问题--详细解释

北城余情 提交于 2020-01-20 02:12:25

问题: 国际象棋棋盘是8 * 8的方格,每个方格里放一个棋子。皇后这种棋子可以攻击同一行或者同一列或者斜线(左上左下右上右下四个方向)上的棋子。在一个棋盘上如果要放八个皇后,使得她们互相之间不能攻击(即任意两两之间都不同行不同列不同斜线),求出一种(进一步的,所有)布局方式。
思路:(粘贴一波网上已有的递归思路,就不码字了)第一个需要解决的小问题就是,如何用数学的语言来表述斜线上重叠的皇后。其实我们可以看到,对于位于(i,j)位置的皇后而言,其四个方向斜线上的格子下标分别是 (i-n,j+n), (i-n,j-n), (i+n,j-n), (i+n,j+n)。当然i和j的±n都要在[0,7]的范围内,保持不越界。暂时抛开越界限制不管,这个关系其实就是: 目标格子(a,b)和本格子(i,j)在同一条斜线上 等价于 |a - i| == |b - j|

然后,从递归的思想来看,我们在从第一行开始给每一行的皇后确定一个位置。每来到新的一行时,对本行的所有可能位置(皇后放在这个位置和前面所有已放置的皇后无冲突)分别进行递归地深入;若某一行可能的位置数为0,则表明这是一条死路,返回上一层递归寻找其他办法;若来到的这一行是第九行(不存在第九行,只不过是说明前八行都已经正确配置,已经得到一个解决方案),这说明得到解决方案。

可以看到,寻找一行内皇后应该摆放的位置这是个递归过程,并且在进入递归时,应该要告诉这个过程的东西包括两个: 1. 之前皇后放置的状态, 2. 现在是第几行。

现在上代码:

def queen(A, cur=0):
    if cur == len(A):
        for i in A:
            print(' - ' * i, 'Q', ' - ' * (7 - i)) # 格式化输出
        print('=' * 23)
        return
    for col in range(len(A)):
        A[cur] = col # 保存当前皇后所在的位置:cur是当前皇后的行号,col是当前皇后的列号
        no_coflict = True # 假设两个皇后之间不存在冲突
        #判断当前皇后与之前所有的恍惚是否存在冲突
        for index in range(cur): # 上index个皇后:index是上个恍惚的行号,A[index]是上个皇后的列号
            if A[index] == col: # 判断是否同列
                no_coflict = False
                break
            # 判断两个皇后是否同斜线等价于两个皇后横坐标之差的绝对值是否与纵坐标的绝对值之差相等|x-xn| == |y-yn|
            row = abs(cur - index)
            column = abs(col - A[index])
            if row == column: # 判断是否同斜线
                no_coflict = False
                break
        if no_coflict: # 两个皇后位置不存在冲突,则继续找下一个皇后的位置
            queen(A, cur + 1)

queen([0] * 8)

推荐一个用动画学习算法的网址,通过动画深入理解递归的运行过程(这个项目已经提供了好多种算法的动图了,包括:暴力、动态规划、回溯、分治、贪心等多种类型算法):
https://algorithm-visualizer.org/

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!