1. 程式人生 > >利用python的生成器解決八皇后問題

利用python的生成器解決八皇后問題

最近在學python的時候看到生成器部分,其中便用到生成器去解決八皇后問題,著實讓我感覺python這門語言的魅力。剛看到生成器的時候很疑惑,看書上的介紹感覺也是雲裡霧裡,所以通過程式碼去解決八皇后的問題的過程中也讓我對它有了一點更深入的瞭解,下面的解釋有問題還請大家多多指出和糾正。

首先來看看什麼是生成器
任何包含yield語句的函式稱為生成器!除了名字不同以外,它的行為和普通的函式也有很大的區別。這就在於它不是像return那樣返回值,而是每次產生多個值。每次產生一個值(使用yield),函式就會被凍結:即函式停在那個等待被重新喚醒。函式被重新喚醒後就從停止的那點開始執行。
先來一個簡單的生成器的應用: 將一個列表中的所有數字一次打印出來
def flatten(nested):
try:
for sublist in nested:
for element in flatten(sublist):
yield element
#這裡的採用try/except是為了捕獲TypeError這個異常,因為我下面提供的nested中除了含有列表的元素
#還有int型別的元素6
except TypeError:
yield nested
if __name__== '__main__':
nested = [[1,2,3],[4,5],6,[7,8]]
print list(flatten(nested))

上面這個程式碼採用的是遞迴生成器的方法去實現依次列印nested中的元素。 輸出的結果為:[1, 2, 3, 4, 5, 6, 7, 8]
對生成器有了一點了解接下來去解決八皇后問題:
首先,什麼是八皇后問題? 在國際象棋棋盤上(8*8)放置八個皇后,使得任意兩個皇后之間不能在同一行,同一列,也不能位於同於對角線上。問共有多少種不同的方法,並且指出各種不同的放法。
首先我們寫一個conflict函式來判斷下一個皇后的位置是否和前面的皇后的放置位置產生衝突
def conflict(state,nextX):
nextY = len(state)
for i in range(nextY):
if abs(state[i] - nextY) in (0, nextY - i):
return True
return False

state是表示用來表示皇后位置放置資訊的元素,比如state[0] = 3, 表示第一行的皇后放置在第四列(列數是從0開始計數的) 上面最關鍵的一行程式碼為
if abs(state[i] - nextY) in (0, nextY - i)
這個是用來判斷這個當前皇后的位置是否與之前皇后位置有衝突,(state[i]-nextY) in (0,i),其中state[i]-nextY=0表示在它的正上方,state[i]-nextY=i表示在對角線上。 接下來用遞迴生成器來解決這個問題:
def queens(num = 8, state=()):
for pos  in range(8):
if not conflict(state, pos):
if len(state) == num - 1:
yield (pos,)
else:
for result in queens(num, state + (pos,)):
yield (pos,) + result
main函式:
if __name__== '__main__':
print list(queens(8))
num = len(list(queens))
print num
輸出結果:[(0, 4, 7, 5, 2, 6, 1, 3), (0, 5, 7, 2, 6, 3, 1, 4).........]    92