回溯法求解N皇后問題

2021-07-16 13:34:08 字數 2736 閱讀 8450

原始出處 、作者資訊和本宣告。否則將追究法律責任。

回溯法:也稱為試探法,它並不考慮問題規模的大小,而是從問題的最明顯的最小規模開始逐步求解出可能的答案,並以此慢慢地擴大問題規模,迭代地逼近最終問題的解。這種迭代類似於窮舉並且是試探性的,因為當目前的可能答案被測試出不可能可以獲得最終解時,則撤銷當前的這一步求解過程,回溯到上一步尋找其他求解路徑。

為了能夠撤銷當前的求解過程,必須儲存上一步以來的求解路徑,這一點相當重要。

光說不做沒意思,用學過的演算法題來運用一下。

n 皇后問題:在乙個 n * n 的西洋棋棋盤中,怎樣放置 n 個皇后才能使 n 個皇后之間不會互相有威脅而共同存在於棋局中,即在 n * n 個格仔的棋盤中沒有任何兩個皇后是在同一行、同一列、同一斜線上。

求解思路:最容易想到的方法就是有序地從第 1 列的第 1 行開始,嘗試放上乙個皇后,然後再嘗試第 2 列的第幾行能夠放上乙個皇后,如果第 2 列也放置成功,那麼就繼續放置第 3 列,如果此時第 3 列沒有一行可以放置乙個皇后,說明目前為止的嘗試是無效的(即不可能得到最終解),那麼此時就應該回溯到上一步(即第 2 步),將上一步(第 2 步)所放置的皇后的位置再重新取走放在另乙個符合要求的地方…如此嘗試性地遍歷加上回溯,就可以慢慢地逼近最終解了。

需要解決的問題:如何表示乙個 n * n 方格棋盤能夠更有效?怎樣測試當前所走的試探路徑是否符合要求?這兩個問題都需要考慮到使用怎樣的資料結構,使用恰當的資料結構有利於簡化程式設計求解問題的難度。

為此,我們使用以下的資料結構:

int column[col] = row

表示第 col 列的第 row 行放置乙個皇后

boolean rowexists[i] = true

表示第 i 行有皇后

boolean a[i] = true

表示右高左低的第 i 條斜線有皇后(按→  ↓ 順序

從1~ 2*n -1 依次編號)

boolean b[i] = true

表示左高右低的第 i 條斜線有皇后(按→  ↑ 順序

從1~ 2*n -1 依次編號)

對應這個資料結構的演算法實現如下:

/** 

* 回溯法求解 n 皇后問題

* @author haolloyin

*/public

class n_queens   

for(int i = 0; i < queensnum * 2; i++)   

}  // 判斷該位置是否已經存在乙個皇后,存在則返回 true

private

boolean i***ists(int row, int col)   

// 主方法:測試放置皇后

public

void testing(int column)   

system.out.println();  

}else   

// 撤銷上一步所放置的皇后,即回溯

rowexists[row] = a[row + column - 1] = b[queensnum + column - row] = false;  

}  }  

}  // 測試

public

static

void main(string args)   

}

當 n = 8 時,求解結果如下(注:橫座標為 列數, 縱座標為 行數

):

(1,1)  (2,5)  (3,8)  (4,6)  (5,3)  (6,7)  (7,2)  (8,4)    

(1,1)  (2,6)  (3,8)  (4,3)  (5,7)  (6,4)  (7,2)  (8,5)    

(1,1)  (2,7)  (3,4)  (4,6)  (5,8)  (6,2)  (7,5)  (8,3)    

... ...  

... ...  

(1,8)  (2,2)  (3,4)  (4,1)  (5,7)  (6,5)  (7,3)  (8,6)    

(1,8)  (2,2)  (3,5)  (4,3)  (5,1)  (6,7)  (7,4)  (8,6)    

(1,8)  (2,3)  (3,1)  (4,6)  (5,2)  (6,5)  (7,7)  (8,4)    

(1,8)  (2,4)  (3,1)  (4,3)  (5,6)  (6,2)  (7,7)  (8,5)   

當 n = 4 時,求解結果如下:

(1,2)  (2,4)  (3,1)  (4,3)    

(1,3)  (2,1)  (3,4)  (4,2)  

有時間的話將輸出的結果列印為直觀一點的符號形式或介面形式更好。

小結:

1、根據問題選擇恰當的資料結構非常重要,就像上面 a 、b 標誌陣列來表示每一條斜線的編號順序以及方向都相當重要。看書的時候也是費了些時間來理解的,呼…另外,queens [col] = row 陣列只是用了一維而不是二維來表示縱橫交錯的方格棋盤上特定位置是否有皇后也是比較經濟而有意思的。

2、正確運用、組織所確定的資料結構到演算法的實現邏輯中也是很重要的,就像**中的 i***ists(int row, int col) 方法內的 (rowexists[row] || a[row + col - 1] || b[queensnum + col - row]) 就是很明確的理解了嘗試放置皇后的位置的 x ,y 座標與斜線之間的數值關係,才使得演算法得以正確執行。當然,對於斜線的編號、順序也是相當重要的。

回溯法求解N皇后問題。

n皇后問題就是 不存在兩個皇后同行或同列,或在同一斜線上。如下圖所示。黑色塊表示其中乙個皇后放在了第二行,第三列。這時,只有綠色圈圈才能放其他的皇后。回溯法的基本思想 確定了解空間的組織結構後,回溯法就從開始結點 根結點 出發,以深度優先的方式搜尋整個解空間。這個開始結點就成為乙個活結點,同時也成為...

回溯法求解n皇后問題

皇后問題 由n n個方塊排成n行n列的正方形稱為 n元棋盤 如果兩個皇后位於棋盤上的同一行或同一列或同一對角線上,則稱她們為互相攻擊,現要求找使n元棋盤上的n個皇后互不攻擊的所有布局。假設棋盤上每一行放置乙個皇后,分別用自然數0,1,2,n 1。首先定義乙個長度為n的一維陣列q,其中每乙個元素去q ...

使用回溯法求解N皇后問題

經典的n皇后問題描述為 在乙個n x n的棋盤上放置n個皇后,要求任意的兩個皇后都不在同一行 同一列或同一條對角線上,問在給定n的情況下有多少種放置的方法。求解n皇后最典型的方法是回溯法,此方法的思路可以概括為 在第一行佔據乙個位置,接著在下一行佔據乙個位置,判斷兩個位置之間是否存在衝突。如果不存在...