趣谈八皇后问题
Money is not everything. There's MasterCard.
金錢不是萬能的, 有時還需要信用卡。
金錢不是萬能的, 有時還需要信用卡。
背景
大話西游之月光寶盒這部電影已經刷了N遍了。每一次看都有每一次的感悟。如果時光可以到倒流,我當初就不應該。。。 悔不當初,悔不當初。
雖然世界上沒有后悔藥,但是算法界卻是有后悔藥的,呢就是---回溯算法。人生不能時光倒流,呢我讓我的算法時光倒流。
?八皇后問題最早是由國際象棋棋手馬克斯·貝瑟爾于1848年提出的,現在都21世紀了,八皇后怎么能滿足我,我決定實現一個N皇后,我想要幾個皇后就要幾個皇后。
所有源碼均已上傳至github:鏈接
N皇后
思考
家家有本難念的經,一個皇后已經了不得了。這N皇后嘛,可得好好處理,不能讓她們打架。可以先聲明一個大小為N的一維數組,來存儲我的這N位皇后。然后分成N個階段。
- 第一個階段隨便選一個位置。
- 第二個階段需要判斷一下我的橫排,豎排,左對角線,右對角線(只需要和第一階段和本身相比即可)有沒有皇后。如果沒有,則繼續往下走。
- 第三個階段以此類推,發現有皇后,不慌,沒關系,時光倒流,到第二階段,重新擺放。
- 第N階段....直到擺出讓每一位皇后滿意的位置。
大概思路就是這樣。
初始化
/*** 皇后數組*/private int[] queens;/*** n皇后*/private int n;/*** 擺法數量*/private int count;/*** 基于8皇后而衍生的N皇后** @param n 皇后的數量*/private SolveNQueens(int n) {queens = new int[n];this.n = n;count = 0;}復制代碼遞歸
雖然代碼很精簡,但是關鍵就在于這個遞歸不好理解。循環里套遞歸,很巧妙。需要一步一步跟一下就知道了。
一維數組存儲的值是皇后的位置(0,n-1)。
默認是要從頭開始的,需要這么調用該方法calNQueens(0)
private void calNQueens(int row) {if (row == n) {printQueens(queens);return;}for (int col = 0; col < n; col++) {if (isSatisfy(row, col)) {queens[row] = col;calNQueens(row + 1);}}}復制代碼是否滿足條件
該方法需要判斷自己的橫豎排,左右對角線是否有皇后。
這里為了便于理解,所以循環里放著三個if。
private boolean isSatisfy(int row, int col) { // System.out.println("(" + row + "," + col + ")");int leftUp = col - 1;int rightUp = col + 1;for (int i = row - 1; i >= 0; --i) {if (queens[i] == col) return false;if (leftUp >= 0 && queens[i] == leftUp) return false;if (rightUp < n && queens[i] == rightUp) return false;--leftUp;++rightUp;}return true;}復制代碼打印
private void printQueens(int[] queens) {for (int row = 0; row < n; row++) {for (int col = 0; col < n; col++) {if (queens[row] == col) System.out.print("1 ");else System.out.print("0 ");}System.out.println();}System.out.println();++count;}復制代碼測試代碼
public static void main(String[] args) {int n = 8;SolveNQueens solveNQueens = new SolveNQueens(n);solveNQueens.calNQueens(0);System.out.println("共計" + solveNQueens.count + "種擺法.");}復制代碼測試結果
4皇后
八皇后(這里是包含了旋轉和對稱的解的解,否則是12種擺法)
end
總結
- 上一篇: 【UML】软件设计说明书 (完结)
- 下一篇: calfcamel 的 2333