Python 学习 用Python第二册 第9章内容解八皇后问题

----用教授的方法学习

目录

1.八皇后问题

2.状态表示(抽象)

3.检测冲突

4.基线条件

5.递归条件

6.结尾


1.八皇后问题

深受大家喜爱的计算机科学谜题:你需要将8个皇后放在棋盘上,条件是任何一个皇后都不能威胁其他皇后,即任何两个皇后都不能吃掉对方。怎样才能做到这一点呢?应将这些皇后放在什么地方呢?

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

在前面描述的问题中,只有8个皇后,但这里假设可以有任意数量的皇后,从而更像现实世界的回溯问题。如何解决这个问题呢?

2.状态表示(抽象)

可简单地使用元组(或列表)来表示可能的解(或其一部分),其中每个元素表示相应行中皇后所在的位置(即列)。因此,如果state[0] == 3,就说明第1行的皇后放在第4列(还记得吧,我们从0开始计数)。在特定的递归层级(特定的行),你只知道上面各皇后的位置,因此状态元组的长度小于8(即皇后总数)。

3.检测冲突

先来做些简单的抽象。要找出没有冲突(即任何一个皇后都吃不到其他皇后)的位置组合,首先必须定义冲突是什么。为何不使用一个函数来定义呢?

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

python 复制代码
def conflict(state, nextX): 
    nextY = len(state) 
    for i in range(nextY): 
        if abs(state[i] - nextX) in (0, nextY - i): 
           return True 
    return False

参数nextX表示下一个皇后的水平位置(x坐标,即列),而nextY为下一个皇后的垂直位置(y坐标,即行)。这个函数对既有的每个皇后执行简单的检查:如果下一个皇后与当前皇后的x坐标相同或在同一条对角线上,将发生冲突,因此返回True;如果没有发生冲突,就返回False。比较难理解的是下面的表达式:

python 复制代码
abs(state[i] - nextX) in (0, nextY - i) 

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

4.基线条件

基线条件:最后一个皇后。对于这个皇后,你想如何处理呢?假设你想找出所有可能的解------给定其他皇后的位置,可将这个皇后放在什么位置(可能什么位置都不行)?可以这样编写代码。

python 复制代码
def queens(num, state): 
    if len(state) == num-1: 
        for pos in range(num): 
           if not conflict(state, pos): 
               yield pos

这段代码的意思是,如果只剩下最后一个皇后没有放好,就遍历所有可能的位置,并返回那些不会引发冲突的位置。参数num为皇后总数,而参数state是一个元组,包含已放好的皇后的位置。例如,假设总共有4个皇后,而前3个皇后的位置分别为1、3和0.

从该图可知,每个皇后都占据一行,而皇后的位置是从0开始编号的

|-----------------------------------------|
| >>> list(queens(4, (1, 3, 0))) [2] |

代码的效果很好。这里使用list旨在让生成器生成所有的值。在这个示例中,只有一个位置符合条件。在图9-1中,在这个位置放置了一个白色皇后。(请注意,颜色没有什么特殊含义,不是程序的一部分。)

5.递归条件

现在来看看这个解决方案的递归部分。处理好基线条件后,可在递归条件中假设来自更低层级(编号更大的皇后)的结果都是正确的。因此,只需在函数queens的前述实现中给if语句添加一个else子句。

递归调用,向它提供的是由当前行上面的皇后位置组成的元组。对于当前皇后的每个合法位置,递归调用返回的是由下面的皇后位置组成的元组。为了让这个过程不断进行下去,只需将当前皇后的位置插入返回的结果开头,如下所示:

python 复制代码
... 
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部分与前面相同,因此可以稍微简化一下代码。另外,还可给参数指定默认值。

python 复制代码
def queens(num=8, 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

如果你觉得这些代码难以理解,用自己的话来描述其作用可能会有所帮助。另外,你可能还记得(pos,)中的逗号必不可少(不能仅用圆括号将pos括起),这样得到的才是元组。

生成器queens提供了所有的解(即所有合法的皇后位置组合)。

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| >>> list(queens(3)) [] >>> list(queens(4)) [(1, 3, 0, 2), (2, 0, 3, 1)] >>> for solution in queens(8): ... print solution ... (0, 4, 7, 5, 2, 6, 1, 3) (0, 5, 7, 2, 6, 3, 1, 4) ... (7, 2, 0, 5, 1, 4, 6, 3) (7, 3, 0, 2, 5, 1, 6, 4) >>> |

如果运行queens时将参数num设置为8,将快速显示大量的解。下面看看有多少个解。

|-----------------------------|
| >>> len(list(queens(8))) |

6.结尾

可以让输出更容易理解些。在任何情况下,清晰的输出都是好事,因为这让查找bug等工作更容易。

python 复制代码
def prettyprint(solution): 
    def line(pos, length=len(solution)): 
         return '. ' * (pos) + 'X ' + '. ' * (length-pos-1) 
    for pos in solution: 
         print(line(pos))

请注意,我在prettyprint中创建了一个简单的辅助函数。之所以将它放在prettyprint中,

是因为我认为在其他地方都用不到它。下面随机地选择一个解,并将其打印出来,以确定它是正

确的。

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| >>> import random >>> prettyprint(random.choice(list(queens(8)))) . . . . . X . . . X . . . . . . . . . . . . X . X . . . . . . . . . . X . . . . . . . . . . . X . . . . X . . . . . X . . . . . |

----end

相关推荐
IT古董13 分钟前
【机器学习】机器学习的基本分类-半监督学习(Semi-supervised Learning)
学习·机器学习·分类·半监督学习
jbjhzstsl31 分钟前
lv_ffmpeg学习及播放rtsp
学习·ffmpeg
青い月の魔女40 分钟前
数据结构初阶---二叉树
c语言·数据结构·笔记·学习·算法
网络安全(king)41 分钟前
网络安全攻防学习平台 - 基础关
网络·学习·web安全
虾球xz1 小时前
游戏引擎学习第59天
学习·游戏引擎
枫零NET2 小时前
学习思考:一日三问(学习篇)之匹配VLAN
网络·学习·交换机
沐泽Mu2 小时前
嵌入式学习-QT-Day07
c++·qt·学习·命令模式
沐泽Mu2 小时前
嵌入式学习-QT-Day09
开发语言·qt·学习
炸毛的飞鼠2 小时前
汇编语言学习
笔记·学习
egekm_sefg3 小时前
webrtc学习----前端推流拉流,局域网socket版,一对多
前端·学习·webrtc