如何解決八皇后問題

2021-10-05 10:16:35 字數 2555 閱讀 5247

八皇后問題指的是在 8*8 的棋盤上,放入 8 個皇后,並且保證在每一行、每一列、以及對角線上都不會同時出現兩個皇后(西洋棋的規則裡面,皇后的攻擊範圍是其所在的橫豎兩條線以及所在的兩條對角線),那麼該如何擺放這 8 個皇后呢?一共有多少種擺放方法?

第一種思路,8*8 的棋盤上一共有 64 個格仔,現在要將 8 個皇后放入到這 64 個格仔當中,就是數學裡面的組合數

第二種思路,由於每個皇后不能在同一行、同一列上,我們在放入第乙個皇后時,隨便選擇一行,我們有 8 種選擇;再放入第二個皇時,此時我們肯定不能放在第乙個皇后所在的行和列了,所以只有 7 種選擇了;再接著我們放入第 3 個皇后,同樣的道理,只能有 6 種選擇了;以此類推,當我們放入第 8 個皇后的時候,就只有 1 種選擇了。所以這種思路,我們一共有 8 的階乘種選擇,即 40320 種選擇,然後我們再從這 4 萬多種組合裡面選擇出符合條件的擺放方式,看上去 4 萬多相比前面的 44 億,小了很多,也算是一種不錯的解法了。

第三種思路:在第二種思路的基礎上,我們在放入第二個皇后的時候,只考慮了與第乙個皇后不同列、不同行,沒有考慮對角線的問題,所以認為第 3 個皇后在放入的時候有 7 中選擇,那如果我們把對角線的問題考慮進去,那第二個皇后的選擇就少了一點。同樣,在放第 3 個皇后的時候,我們再把前面兩個皇后的對角線考慮進去,第三個皇后的選擇也少了,以此類推,到放第 8 個皇后的時候,選擇就更少了,甚至在放第 5 個、第 6 個的時候,就出現了沒有任何選擇可以選的情況了,也就是死路了。這樣總體下來,出現的組合情況肯定是遠遠小於第二種思路的 4 萬多種組合。

對於第三種思路,如果我們出現了死路怎麼辦?假如我們在放第 5 個皇后的時候,出現了無論怎麼放第五個皇后,都會不滿足要求,這個時候就說明,前面 4 個皇后的擺放有問題。那怎麼呢?我們可以先回退到第 4 步,修改第 4 個皇后的擺放位置,然後再繼續嘗試擺放第 5 個皇后。如果第 5 個皇后仍然無法擺放,那再回到第 4 步,再修改第 4 個皇后的位置。如果出現第 4 個皇后可以擺的地方全都嘗試了,第 5 個皇后還是沒有地方可放,那這個時候就說明,第 3 個皇后的位置擺放出了問題,所以重新回到第 3 步,如果後面依舊出現死路,那就依次往後回退,直到找到合適的擺法。

熟悉資料結構與演算法的同學這個時候肯定想到了,這種思路就是回溯思想,先從某一條路開始走,一條路走到黑,出現死胡同了,就回到上乙個路口(回溯),從另乙個方向再次出發,又出現死胡同了,就再返回剛剛的路口,直到將該路口的所有岔道走遍了,如果還是走不通,就繼續向前回溯,回到上上個路口,直到找到出路為止。

回溯的思想很簡單,那麼**該如何實現呢?實現回溯法最常用的方式就是使用遞迴了,下面使用回溯思想,用遞迴**來實現上面 8 個皇后的擺放問題。

首先我們定義乙個長度為 8 的陣列:int result,用來存放每個皇后擺放在哪個地方,陣列的下標表示存放的是第幾行的皇后,元素的值表示的是該行的皇后擺放在哪一列。例如:result[0] = 4 表示第 0 行中的皇后放在第 4 列。

另外再定義乙個方法putqueen(row),含義是往第 row 行中放入乙個皇后,**的骨架如下:

// 用乙個陣列存放每一行的皇后的位置,陣列的下標表示的是行,元素的值表示的是該行的皇后擺放在哪一列

public

int result = new

int[8];

/*** 往第row行中放入皇后,row最開始從0開始

* @param row 第幾行

*/public

void

putqueen

(int row)

for (int column = 0; column 

在每次往某一行的某一列中放入皇后之前,我們需要判斷一下,該行該列是不是在前面幾個皇后的攻擊範圍之內(行、列、對角線)。所以定義了乙個方法isaccessible(row, column),該方法就是來判斷該行該列能不能放入皇后。判斷邏輯是什麼呢?就是從當前行依次向上遍歷,判斷前面幾行的皇后的攻擊範圍是不是會覆蓋到第 row 行第 column 列,具體**如下。

/**

* 判斷第row行,第column列能不能擺放皇后

* @return

*/private

boolean

isaccessible

(int row, int column)

return

true;

}

最後為了方便顯示皇后的擺放位置,寫了乙個列印 8*8 棋盤的方法。

private

void

printqueen

()system.out.println();

}system.out.println("*************************");

}

最終執行結果一共有 92 中擺放方法。

回溯法的思想很簡單,就是在岔口上先選擇一條路走下去,走不通了,就回退到上一步,繼續走,直到嘗試所有的選擇為止。雖然思路簡單,但實現回溯法的**相對而言,不是那麼好寫,經常出現一看就會,一些就錯,筆者作為一名菜鳥就是如此,經常寫錯,尤其是邊界值的地方,因此也建議大家多親自動手敲敲**。

八皇后問題python python解決八皇后問題

運用python的生成器可輕鬆解決八皇后問題 使用元組表示可能的解,其中每個元素表示相應行中皇后所在位置 列 即state 0 3,則說明第一行的皇后在第4列。coding utf 8 import random 檢測衝突 def conflict state,nextx state為各皇后相應位置...

c解決八皇后問題

問題描述 這是乙個經典的關於組合學的問題 在乙個西洋棋中的的棋盤上放置8個皇后,為了使其中的任何2個皇后都不能相互 攻擊 希望尋求8個皇后的安全放置位置。該問題的不能相互 攻擊 相當於要求任意兩個皇后不能在同一行 同一列或同一斜線上。求解可能的方案及方案數。思路 一般採用回溯法。易知,每行肯定有乙個...

scala解決八皇后問題

八皇后問題,是乙個古老而著名的問題,是 回溯演算法 的典型案例。該問題是國際西洋棋棋手馬克斯 貝瑟爾於1848年提出 在8 8格的西洋棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法?defnqueens n int set list int p...