您的位置:首页 > 编程语言 > Python开发

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

2014-06-29 16:30 295 查看
八皇后问题是一个经典的问题:

为了保证各个皇后的安全,在一个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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: