Python中的生成器在八皇后问题上的应用

八皇后问题是一个经典的问题:

             为了保证各个皇后的安全,在一个8X8的矩阵上,必须保证任意两个皇后不能处于同一行、同一列以及同一条对角线上,那么安全的摆法总共有多少种呢?

好,一步步来。老话说得好,程序=数据结构+算法。我们先来选一个合适的数据结构。很明显,问题中提到了矩阵,那么二维数组肯定是可以的,但用二维数组是不是有点牛刀杀鸡的感觉?想想,8X8的矩阵我们最终只会存储8个元素,还有56个空间被浪费了。再看一下问题的条件:元素不能处于同一行,也就是每一行我们只会存储一个元素,即:f(x)=pos,x表示行号,pos表示皇后在x行的安全位置(也就是列号),而x又是连续的(1,2,3,...,8),所以说,针对这个问题,一维数组足矣:数组下标表示行号,对应值来表示位置。

好了,数据结构有了,想想算法怎么去实现。

皇后肯定是一个个的试探性的去放,如果暂时安全就放在当前位置,不安全就换一个位置试试,如果这一行都没有合适的位置,那就回到前一行,让前一行的皇后换个安全的位置,再到下一行继续试。

OK,不用多说了,典型的回溯。我们用递归来实现。

不借助迭代器,代码如下:

def poschk(pos,positions,n):
    t1=not pos in positions
    
    t2=True
    tmpx=len(positions)-1
    tmpy=pos-1
    while tmpx>=0 and tmpy>=0:
        if positions[tmpx]==tmpy:
            t2=False
            break
        tmpx-=1
        tmpy-=1
    
    t3=True
    tmpx=len(positions)-1
    tmpy=pos+1
    while tmpx>=0 and tmpy<n:
        if positions[tmpx]==tmpy:
            t3=False
            break
        tmpx-=1
        tmpy+=1
        
    return t1 and t2 and t3


def queen(positions,num):
    if(len(positions)==num):
        print positions
    for pos in range(num):
        t=poschk(pos,positions,num)
        if t:
            positions.append(pos)
            queen(positions,num)
            positions.pop()
            
if __name__=='__main__':
    positions=[]
    num=8
    queen(positions,num)

上面的代码基本符合要求,至少所有的排列方式都能打印出来了,那么如果不想打印,而是把结果存起来呢?那就在queen函数里再加一个list参数?这样可行,但是不是有点别扭,因为这个参数在queen的绝大数调用中都是没用的,只有最后才会用来装一下结果。

好,看看Python的迭代器是怎么解决这个问题的。代码如下(除queen函数以外其他地方不变)

def queen(positions,num):
    for pos in range(num):
        t=poschk(pos,positions,num)
        if t and len(positions)==num-1:
            yield (pos,)
        if t and len(positions)<num-1:
            for next_pos in queen(positions+(pos,),num):
                yield (pos,)+next_pos

这样的话,针对排列结果就好处理多了。

比如看看有多少种排列方式:

print len(list(queen(positions,num)))   //92
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值