CDays-3 習題三 (八皇后問題)及相關內容解析。Python 基礎教程


又是八皇后問題。

似乎每種語言中都會出現八皇后問題來告訴你遞歸算法怎么玩。

讓我們先百度一下八皇后問題。於是你發現了百度百科,好長的詞條,里面基本包括了所有主流語言的例程。讓我們點擊Python看一下。

image

我了個大槽,這是什么玩意,木有縮進,而且那個庫也沒見過,趁機搜一下。

好像是迭代器里面的東西。迭代器又是什么。 好吧,一個算法問題已經引出了另一個常識問題了。讓我們先停在這里吧。去參考另一篇日志吧,還沒寫。><

我修復了下上面的程序。

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

image

顯然是可以運行的。牛逼吧。

但是我們可以知道,這里面是有重復的,因為從棋盤是對稱的,每行判別的方法不可避免的出現重復解。但這是正確的完整解92個。

這個程序對於我們初學者來說太過強大了,不過它完美的體現了Python的優美。

讓我們看一看比較普通的想法。

好像直到現在我們還不知道什么是八皇后問題,看一下哈。

在8X8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。

image

就是類似於這種布局。

如果我們在棋盤的的任何一個位置放一個皇后,

image

那么我們就可以得到

image

這八個方向不能有另外的皇后了,根據這個現象,我們可以肯定,一行有且只有一個皇后,每一列有且只有一個皇后。

我們先預想一個循環,對每一排的每個位置編號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
image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM