利用生成器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种

原文地址:https://www.cnblogs.com/stonenox/p/11217097.html

时间: 2024-10-02 10:20:40

利用生成器yield 递归解决八王后问题的相关文章

利用 Python yield 创建协程将异步编程同步化

在 Lua 和 Python 等脚本语言中,经常提到一个概念: 协程.也经常会有同学对协程的概念及其作用比较疑惑,本文今天就来探讨下协程的前世今生. 首先回答一个大家最关心的问题:协程的好处是什么? 通俗易懂的回答: 让原来要使用 异步 + 回调 方式写的非人类代码,可以用看似同步的方式写出来. 1.回顾同步与异步编程 同步编程即线性化编程,代码按照既定顺序执行,上一条语句执行完才会执行下一条,否则就一直等在那里. 但是许多实际操作都是CPU 密集型任务和 IO 密集型任务,比如网络请求,此时不

函数嵌套 ,名称空间与作用域 ,闭包函数 ,装饰器 ,迭代器, 生成器 三元表达式,列表解析,生成器表达式 递归与二分法, 内置函数

函数嵌套名称空间与作用域闭包函数装饰器迭代器生成器三元表达式,列表解析,生成器表达式递归与二分法内置函数--------------------------------------------函数的嵌套调用:在调用一个函数的过程中,又调用了其他函数函数的嵌套定义:在一个函数的内部,又定义另外一个函数def max(x,y): if x>y: return x else: return ydef max1(a,b,c,d): res=max(a,b) res2=max(res,c) res3=ma

迭代器、生成器以及利用生成器实现单线程的异步并发

1.迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素.迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁.这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件 特点: 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容 不能随机访问集合

20150410 递归实现八皇后问题

20150410 递归实现八皇后问题 2015-04-10 Lover雪儿 十九世纪著名的数学家高斯1850年提出: 在8x8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意的连个皇后都不能处于同一行.同一列或者统一斜线,问有多少种摆法. 以下是其中一种解法,如图所示: 当年高斯先生没日没夜的计算,得出结论是76种. 其实正确的结论是92中,此处我们就来编程计算一下正确的答案. 1 //八皇后问题 2 #include <stdio.h> 3 4 static int count = 0;

python基础一 ------利用生成器生成一个可迭代对象

#利用生成器生成一个可迭代对象#需求:生成可迭代对象,输出指定范围内的素数,利用生成器产生一个可迭代对象#生成器:本身是可迭代的,只是 yield 好比return返回,yield返回后函数冻结状态,当再次调用时从冻结状态开始 1 class PrintNumbers(object): 2 """docstring for PrintNumbers""" 3 def __init__(self, start,end): 4 self.start

每天刷个算法题20160526:BFS解决八数码问题(九宫格问题)

版权所有.所有权利保留. 欢迎转载,转载时请注明出处: http://blog.csdn.net/xiaofei_it/article/details/51524864 为了防止思维僵化,每天刷个算法题.已经刷了几天了,现在发点代码. 我已经建了一个开源项目,每天的题目都在里面: https://github.com/Xiaofei-it/Algorithms 绝大部分算法都是我自己写的,没有参考网上通用代码.读者可能会觉得有的代码晦涩难懂,因为那是我自己的理解. 最近几天都是在写一些原来的东西

python学习之生成器yield

python学习之生成器yield **yield的作用是使函数生成一个结果序列而不是一个值,任何使用yield的函数都称为生成器,调用生成器会创建一个对象,该对象通过连续调用next()或者__next__()方法生成结果序列** 一般情况 >>> def count(n,m): >>> print('这是一个循环外部测试') >>> while n>0: >>> print('这是一个循环内部测试') >>>

汉诺塔递归解决方法经典分析

一位法国数学家曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针.印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔.不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面.僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔.庙宇和众生也都将同归于尽. 虽然这只是一个传说,但也给我们提出了一个问题,

C语言解决八皇后问题

1 #include <stdio.h> 2 #include <stdlib.h> 3 4 /* this code is used to cope with the problem of the eight queens. 5 * array borad[9][9] is a virtual borad. 6 * line 0 and volumn 0 is ignored. 7 * at first we find a place to set a queen on it,