回溯法(一)——n皇后問題
阿新 • • 發佈:2022-05-03
問題描述
在一個n*n的棋盤上放置皇后,要求:一個皇后的同一行、同一列、同一條對角線上不允許出現其他皇后。請給出所有的放置方案。
演算法思路
思路很簡單,由於每行每列不能出現兩個皇后,因此每行只能放一個皇后,那麼第i行中皇后究竟應該放哪兒呢?我們可以從第i行第一列開始依次向後逐格判斷,看看若放在當前位置是否會衝突,若不衝突,則繼續考慮下一行,若衝突,則繼續向後移動一格,再判斷。 若i行所有的位置都不滿足,則回溯,將i-1行皇后的位置往後移動,直到找到一個合理的位置,再繼續從前往後尋找i行的位置。
示例
求解4皇后問題。
- 尋找第一行插入點:首先將Q放置a[0][0],無衝突;
- 尋找第二行插入點:a[1][0]、a[1][1]均衝突,a[1][2]可行;
- 尋找第三行插入點:發現所有格子都衝突,此時要發生回溯!
- 回到第二行,繼續向後尋找插入點,找到a[1][3];
- 尋找第三行插入點:a[2][1]
- 尋找第四行插入點:發現所有位置都衝突,則回溯!
- 尋找第三行插入點:發現全都衝突,則繼續回溯;
- 尋找第二行插入點:發現全都衝突,則繼續回溯;
- 尋找第一行插入點:a[0][1];
- 尋找第二行插入點:a[1][3];
- 尋找第三行插入點:a[2][0];
- 尋找第四行插入點:a[3][2],此時找到一種方案。
資料結構
result陣列:儲存結果集。
- 下標表示行號;
- result[i]表示第i行皇后的列號。
程式碼實現
/** * N皇后問題 * @param n 矩陣規模 * @param i 行號 * @param result 皇后的結果集(下標表示行號,值表示列號) */ void NQueen( int n, int i, int[] result ){ for( int j=0; j<n; j++ ){ if ( canPlace(n,i,j,result) ){ result[i] = j; if ( i==n-1 ) { printResult(result); } else { NQueen(n,i+1,result); } } } } /** * 判斷第i行第j列能不能放 * @param n 矩陣規模 * @param i 行號 * @param j 列號 * @param result 皇后的結果集(下標表示行號,值表示列號) */ private boolean canPlace(int n, int i, int j, int[] result){ for( int z=0; z<i; z++ ){ // 判斷列號是否相同、是否在對角線上(長、寬是否相等) if ( j==result[z] || (i-z)==Math.abs(j-result[z]) ) return false; } return true; } /** * 列印結果集 * @param result 結果集 */ private void printResult(int[] result){ for( int i=0; i<result.length; i++ ){ System.out.println("第"+i+"行,第"+result[i]+"列"); } }