遞迴解決八皇后問題
阿新 • • 發佈:2022-04-17
√八皇后問題說明
-
八皇后問題,是一個古老而著名的問題,是回溯演算法的典型案例。
-
該問題是國際西洋祺棋手馬克斯貝瑟爾於1848年提出:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊
-
即:任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。
√八皇后思路分析
1)第一個皇后先放第一行第一列 arr[8] = {0,0}
2)第二個皇后放在第二行第一列、然後判斷是否OK,
3)繼續第三個皇后,還是第一列、第二列.直到第8個皇后也能放 在一個不衝突的位置,算是找到了一個正確解
4)當得到一個正確解時,在棧回退到上一個棧時,就會開始回溯,即 將第一個皇后,放到第一列的所有正確解,全部得到.
5)然後回頭繼續第一個皇后放第二列,後面繼續迴圈執行1,2,3,4的 步驟
說明:理論上應該建立一個二維陣列來表示棋盤,但是實際上可以通 過演算法,用一個一維陣列即可解決問題
例如 : arr[8]={0,4,7,5,2,6,1,3} ,我們可以使用這樣的一維陣列來解決問題, 例如該陣列 就是將皇后擺放到 ,第一行的第一列 ,第二行的第五列 .........
程式碼示例(通過視訊參考,對著敲出來的)
public class Eight_questions {
public static void main(String[] args) {
checkerboard c1 = new checkerboard();
c1.check(8,0);
}
}
class checkerboard {
int [] arr= new int[8];
int count = 0;
public void check(int n, int index) {
if (n == index){
for (int i = 0;i < n ;i++){
System.out.print(arr[i]+" ");
}
count+=1;
System.out.println();
System.out.println("第"+count+"種擺放");
}else {
for (int i = 0;i < n ;i++){
//此時的n代表列
arr[index] = i;
//第index行第i列
if (judge(index)){
check(n,index + 1);
}
}
}
}
public boolean judge(int index){
for (int i=0;i<index;i++){
if (arr[i]==arr[index]||Math.abs(index - i)==Math.abs(arr[index]-arr[i])){
return false;
}
}
return true;
//如果不起衝突就返回true
}
}
實際分析一下程式碼
class checkerboard
建立一個類 ,用於實現八皇后的棋盤填充
int [] arr= new int[8];
//在類中建立一個全域性變數陣列,因為下面有兩個方法需要使用到
public void check(int n, int index) {
//建立方法check,傳參的引數 n為皇后棋子的個數,index表示從第幾行開始
if (n == index){
//如果棋子個數和和行數一致表示皇后已經全部下完
for (int i = 0;i < n ;i++){
//迴圈行數對陣列進行遍歷,然後將陣列的內容打印出來
System.out.print(arr[i]+" ");
}
count+=1;
System.out.println();
System.out.println("第"+count+"種擺放");
}
//如果陣列沒有完成填充(也就是八皇后的棋子沒有下完)
else {
for (int i = 0;i < n ;i++)
//迴圈
{
//此時的n代表列
arr[index] = i;
//迴圈填充陣列的內容
//第index行第i列
if (judge(index)){
//接收judge方法來判斷這個位置是否符合規範,若符合規範就執行下面的遞迴
check(n,index + 1);
//遞迴呼叫方法,每次新增都會增加一次行數
}
}
}
public boolean judge(int index){
//這個方法主要用於判斷皇后放置是否合法,接收引數index表示每行進行判斷
for (int i=0;i<index;i++){
//迴圈
if (arr[i]==arr[index]||Math.abs(index - i)==Math.abs(arr[index]-arr[i])){
//判斷陣列的上下兩行放置的列是否一致(如若一致表示皇后在同一列觸犯了規則)
//判斷陣列的上下兩行,通過兩個位置橫縱座標互減如果數值一致就說明在一條斜線之上
//同時由於不可能同行因此不判斷同行的情況
return false;
//如果不符合判斷就返回false
}
}
return true;
//如果符合規範就返回true
}