Python用迭代(yield)和递归解决八皇后问题

Python014

Python用迭代(yield)和递归解决八皇后问题,第1张

国际象棋的皇后行走具有最高的灵活性,可以横、竖、斜共八个方向无限步行走。你需要将国际象棋8个皇后放在棋盘上,条件是任何一个皇后都不能威胁其他皇后,即任何两个皇后都不能吃掉对方。

分析:在棋盘的第一行尝试为第一个皇后选择一个位置,再在第二行尝试为第二个皇后选择一个位置,依次类推。在发现无法为一个皇后选择合适的位置后,回溯到前一个皇后,并尝试为它选择另一个位置。当八个皇后都放在棋盘上时即得到一种解。

用元组(其他序列也可以)表示可能的解(或一部分),例如(1,3,5)表示当前共摆放了三个皇后,第一个皇后在1行1列,第二个皇后在2行3列,第三个皇后在3行5列。

当前状态state,下一个皇后在下一行的next_x位置,根据皇后的行走规则,如果已有的皇后可以吃掉下一个皇后,则表示有冲突,否则没有。

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

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

abs(state[i] - next_x) in (0, next_y - i) 表示两个皇后的水平距离为0或等于垂直距离时为真、否则为假。

凡是线性回溯都可以归结为右递归的形式,也即是二叉树,因此对于只要求一个解的问题,采用右递归实现的程序要比回溯法要优美的多。

[py] view plain copy

def Test(queen,n):

'''''这个就不用说了吧,就是检验第n(下标,0-7)行皇后的位置是否合理'''

q=queen

for i in xrange(n):

if queen[i]==q or queen[i]-q==n-i or queen[i]-q==i-n:return False

return True

def Settle(queen,n):

'''''这个负责安置第n(下标,0-7)行皇后,每次调用,皇后都至少会移动一步'''

queen

+=1

while queen

<8 and not Test(queen,n):queen

+=1

return queen

<8

def Solve(queen,n):

'''''这个负责解决第n(下标,0-7)行皇后的安置以及随后所有皇后的安置'''

if n==8:#安置完所有皇后了,故输出列表

print queen

return True#如果设为假,则会尝试所有的安置方案

else:

queen

=-1#初始化第n行皇后的起始位置(起始位置-1,可安置在0-7)

while Settle(queen,n):#如果成功安置皇后

if Solve(queen,n+1):#安置其余皇后

return True#成功安置,返回真

return False#失败,返回假

if __name__=='__main__':

Solve([-1 for i in range(8)],0)#列表的值可以随便设置,因为会初始化

#虽然我们没有进行回溯,但事实上,我们每一个参数相同的Solve函数都尝试了多次

#输出:[0, 4, 7, 5, 2, 6, 1, 3]

#比回溯法容易多了吧

pos是从0到num-1走的

pos=0时程序走这一段:

for result in queens(num, state + (pos,)):

yield (pos,) + result

就是先找第一个位置