又是八皇后問題。
似乎每種語言中都會出現八皇后問題來告訴你遞歸算法怎么玩。
讓我們先百度一下八皇后問題。於是你發現了百度百科,好長的詞條,里面基本包括了所有主流語言的例程。讓我們點擊Python看一下。
我了個大槽,這是什么玩意,木有縮進,而且那個庫也沒見過,趁機搜一下。
好像是迭代器里面的東西。迭代器又是什么。 好吧,一個算法問題已經引出了另一個常識問題了。讓我們先停在這里吧。去參考另一篇日志吧,還沒寫。><
我修復了下上面的程序。
from itertools import permutations for vec in permutations(range(8)): if (8 == len(set(vec[i]+i for i in range(8)))== len(set(vec[i]-i for i in range(8)))): print vec
顯然是可以運行的。牛逼吧。
但是我們可以知道,這里面是有重復的,因為從棋盤是對稱的,每行判別的方法不可避免的出現重復解。但這是正確的完整解92個。
這個程序對於我們初學者來說太過強大了,不過它完美的體現了Python的優美。
讓我們看一看比較普通的想法。
好像直到現在我們還不知道什么是八皇后問題,看一下哈。
在8X8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。
就是類似於這種布局。
如果我們在棋盤的的任何一個位置放一個皇后,
那么我們就可以得到
這八個方向不能有另外的皇后了,根據這個現象,我們可以肯定,一行有且只有一個皇后,每一列有且只有一個皇后。
我們先預想一個循環,對每一排的每個位置編號0~7 。
我們對每一個位置都應該有可行性判定,即該位置的上下左右,正負對角線有沒有皇后,如果有就跳過該位置。
這樣的做法應該有幾個數組來保存行列,正負對角線狀態,讓我們先定義全局變量,並且做一些初始化工作。
global col #定義一些全局變量 global row global pos_diag global nag_diag global count ''' =========================================================== ''' col = [] #矩陣列的列表,存儲皇后所在列,若該列沒有皇后,則相應置為1,反之則0 row = [] #矩陣行的列表,存放每行皇后所在的列位置,隨着程序的執行,在不斷的變化中,之間輸出結果 pos_diag = [] #正對角線,i-j恆定,-7~0~7,並且b(i)+7統一到0~14 nag_diag = [] #負對角線,i+j恆定,0~14 count = 0 for index in range(0, 8): #一些初始化工作 col.append(1) row.append(0) for index in range(0, 15): pos_diag.append(1) nag_diag.append(1)
這樣,我們有了一張宏觀的表,告訴我們哪一行,哪一列,那幾排對角線上面有皇后。
然后讓我們定義判定程序。
def do_queen(i): ''' 生成所有正確解 @param i: 皇后的數目,即第幾個皇后。從0計數 ''' for j in range(0, 8): #依次嘗試0~7位置 if col[j] == 1 and pos_diag[i-j+7] == 1 and nag_diag[i+j] == 1: #若該行,正對角線,負對角線上都沒有皇后,則放入i皇后 row[i] = j col[j] = 0 #調整各個列表狀態 pos_diag[i-j+7] = 0 nag_diag[i+j] = 0 if i < 7: do_queen(i+1) #可遞增或遞減 else: print row #產生一個結果,輸出 col[j] = 1 #恢復各個列表狀態為之前的 pos_diag[i-j+7] = 1 nag_diag[i+j] = 1
把這兩段程序拼接起來就完成了,下面給出完整的算法。
global col #定義一些全局變量 global row global pos_diag global nag_diag global count def output(): ''' 輸出一種有效結果 ''' global count print row count += 1 def do_queen(i): ''' 生成所有正確解 @param i: 皇后的數目 ''' for j in range(0, 8): #依次嘗試0~7位置 if col[j] == 1 and pos_diag[i-j+7] == 1 and nag_diag[i+j] == 1: #若該行,正對角線,負對角線上都沒有皇后,則放入i皇后 row[i] = j col[j] = 0 #調整各個列表狀態 pos_diag[i-j+7] = 0 nag_diag[i+j] = 0 if i < 7: do_queen(i+1) #可遞增或遞減 else: output() #產生一個結果,輸出 col[j] = 1 #恢復各個列表狀態為之前的 pos_diag[i-j+7] = 1 nag_diag[i+j] = 1 if __name__ == '__main__': col = [] #矩陣列的列表,存儲皇后所在列,若該列沒有皇后,則相應置為1,反之則0 row = [] #矩陣行的列表,存放每行皇后所在的列位置,隨着程序的執行,在不斷的變化中,之間輸出結果 pos_diag = [] #正對角線,i-j恆定,-7~0~7,並且b(i)+7統一到0~14 nag_diag = [] #負對角線,i+j恆定,0~14 count = 0 for index in range(0, 8): #一些初始化工作 col.append(1) row.append(0) for index in range(0, 15): pos_diag.append(1) nag_diag.append(1) do_queen(0) #開始遞歸,先放一個,依次遞增,反過來,從7開始遞減也可 print 'Totally have %d solutions!' % count
