• Python3的八皇后问题


    一、生成器的回溯(Generator Traceback)

    对于逐步得到结果的复杂递归算法,非常适用生成器来实现。

    要在不使用生成器的情况下实现这些算法,通常必须通过额外的参数来传递部分结果,让递归能够接着往下计算。

    通过使用生成器,所有的递归调用都只需生成其负责部分的结果。

    二、问题

    八皇后:你需要将8个皇后放在棋盘上,条件是任何一个皇后都不能威胁其他皇后,即不能在同一列和对角线。

    这是一个典型的回溯问题:在棋盘的第一行尝试为第一个皇后选择一个位置,再在第二行尝试为第二个皇后找一个位置,以此类推。在发现无法为一个皇后选择合适的位置后,回溯到前一个皇后,并尝试为她找另一个位置。最后,要么尝试完所有的可能性,要么找到答案。

    当然现实中的问题可能不仅仅是八个,可以是任意多个。

    三、状态表示

    可简单的使用元组(或列表)来表示可能的解(或其中一部分),其中每个元素表示相应行中皇后所在的位置(列)。

    如state[0] == 3,就说明第一行的皇后放在第四列(因为是从0开始计数的,范围[0,7])。

    在特定的递归层级(特定的行),你只知道上面各皇后的位置,因此状态元组的长度小于8(即皇后总数)。

    四、检测冲突

    函数conflict(冲突)接受(用状态元组表示的)既有皇后的位置,并确定下一个皇后的位置是否会导致冲突。

    1 def conflict(state,nextX):  #conflict 冲突
    2     nextY = len(state)  # num = [1,2,3] len(num) == 3
    3     for i in range(nextY):# range取不到nextY,range(3)取:0,1,2
    4         if abs(state[i] - nextX) in (0, nextY - i):  # abs()取绝对值
    5             return True
    6     return False

    nextX表示下一个皇后的水平位置(X坐标,即列);

    nextY表示下一个皇后的垂直位置(y坐标,即行)

    该函数对既有的每个皇后执行简单的检查:如果下一个皇后与当前皇后的x坐标相同或在同一条对角线上,将发生冲突,因此返回True;如果没有冲突就返回False。

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

    表示:如果下一个皇后和当前皇后的水平距离为0(在同一列)或与它们的垂直距离(位于一条对角线上),这个表达式为真,否则为假。

    五、基线条件

    最后一个皇后

    def queens(num, state):
        if len(state) == num - 1:
            for pos in range(num):   # pos:位置
                if not conflict(state, pos):
                    yield pos

    如果只剩下最后一个皇后没有放好,就遍历所有可能的位置,并返回那些不会引发冲突的位置。

    num为皇后总数

    state是一个元组,包含已放好的皇后的位置。

    六、递归条件

    你希望递归调用返回什么样的结果?你希望它返回当前行下面所有皇后的位置。

    假设这些位置是以元组的方式返回的,因此需要修改基线条件,使其返回一个(长度为1的)元组。

    对于递归调用,向它提供的是由当前行上面的额皇后位置组成的元组。对于当前换后的每个合法位置,递归调用返回的是由下面的皇后位置组成的元组。

    为了让这个过程不断进行下去,只需将当前皇后的位置插入返回的结果开头。

    def queens(num, state):
        if len(state) == num - 1:
            for pos in range(num):
                if not conflict(state, pos):
                    yield pos
        else:
            for pos in range(num):
                if not conflict(state, pos):
                    for result in queens(num, state + (pos, ))
                        yield (pos,) + result

    这里的for pos和if not conflict部分与前面相同,所以可以简化代码:

    def queens(num = 8, state = ()):
        if 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

    七、清晰的输出

    def pretyprint(solution):
        def line(pos, length = len(solution)):
            return '. '*(pos) + 'X '+'. '*(length - pos - 1)
        for pos in solution:
            print(line(pos))
    
    pretyprint(random.choice(list(queens(8))))
  • 相关阅读:
    学习Python比较好的书籍推荐
    将Python分成7个阶段学习,你会发现学习Python真的很简单
    web前端开发学习 自学web前端需要掌握哪些知识点?
    零基础想转行从事Python?需要掌握如下技能
    每日干货丨C++语言主流开发工具推荐!
    适合零基础人群学习的Python入门教程
    Python爬虫学习教程 猫眼电影网站视频爬取!【附源码】
    Python爬虫学习教程 bilibili网站视频爬取!【附源码】
    Python爬虫技术要学到什么程度才可以找到工作?
    零基础如何高效的学习好Python爬虫技术?
  • 原文地址:https://www.cnblogs.com/gepu1991/p/9153043.html
Copyright © 2020-2023  润新知