1. 程式人生 > 其它 >回溯法(一)——n皇后問題

回溯法(一)——n皇后問題

問題描述

在一個n*n的棋盤上放置皇后,要求:一個皇后的同一行、同一列、同一條對角線上不允許出現其他皇后。請給出所有的放置方案。

演算法思路

思路很簡單,由於每行每列不能出現兩個皇后,因此每行只能放一個皇后,那麼第i行中皇后究竟應該放哪兒呢?我們可以從第i行第一列開始依次向後逐格判斷,看看若放在當前位置是否會衝突,若不衝突,則繼續考慮下一行,若衝突,則繼續向後移動一格,再判斷。 若i行所有的位置都不滿足,則回溯,將i-1行皇后的位置往後移動,直到找到一個合理的位置,再繼續從前往後尋找i行的位置。

示例

求解4皇后問題。

  1. 尋找第一行插入點:首先將Q放置a[0][0],無衝突;
  2. 尋找第二行插入點:a[1][0]、a[1][1]均衝突,a[1][2]可行;
  3. 尋找第三行插入點:發現所有格子都衝突,此時要發生回溯!
  1. 回到第二行,繼續向後尋找插入點,找到a[1][3];
  2. 尋找第三行插入點:a[2][1]
  3. 尋找第四行插入點:發現所有位置都衝突,則回溯!
  1. 尋找第三行插入點:發現全都衝突,則繼續回溯;
  2. 尋找第二行插入點:發現全都衝突,則繼續回溯;
  3. 尋找第一行插入點:a[0][1];
  4. 尋找第二行插入點:a[1][3];
  5. 尋找第三行插入點:a[2][0];
  6. 尋找第四行插入點: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]+"列"); 
    }
}