八皇后问题是一个经典的问题:
为了保证各个皇后的安全,在一个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