1. 程式人生 > >回溯法解決N後問題(java描述)

回溯法解決N後問題(java描述)

1.問題描述:

N後問題就是在一個N*N的棋盤上放置N個皇后,要求這N個皇后中的任何兩個皇后不在同一行或同一列或同一斜線上。

2.演算法設計:

使用x[1...n]來表示問題的解。x[i]表示第i個皇后放在棋盤的第i行第x[i]列。因為i是唯一的,所以i是不可能相同的,所以在判斷皇后是否能放置時只需要判斷當前放置的皇后位置所在的列以及所在的斜線上是否有皇后即可。比較兩個皇后x[i],x[j]時,判斷它們是否在同一列上可以用x[i]=x[j]是否相等來判斷;判斷它們是否在同一斜線上可以用|i-j|=|x[i]-x[j]|是否相等來判斷(即判斷兩點之間的斜率是否為1)。

解決N後問題最經典的方法是回溯法,即從第一行第一列開始放置皇后,然後從第二行第一列放置一個皇后判斷當前位置能否放置皇后;若不能就判斷當前行的當前列的下一列是否能放置皇后,以此類推;如果在一行中所有的列都不能放置皇后,那麼就回到上一行放置皇后位置,判斷當前放置皇后位置的當前行的下一列。

3.程式碼實現(java描述)

public class NQueen {
final static int N=8;
final static int queen[]=new int [N];
static int sum=0;
//N皇后問題:在N*N的棋盤上防放置N個棋子,使得所有的棋子都不能在同一行、列、和斜對角線上
//使用一維陣列來表示問題的解,x[i]表示在第i行第x[i]列放置皇后

public static void main(String[] args) {
for(int i=0;i<N;i++)
solveQueen(i);
}

//判斷當前放置的皇后能否放置
//n表示第i行
static boolean isPlace(int n){

//迴圈從第一行到當前行的上一行
for(int i=0;i<n;i++){
//只要判斷列和斜線不相同就可以了
if(queen[i]==queen[n] || Math.abs(i-n)==Math.abs(queen[i]-queen[n])){
return false;
}
}

return true;
}

//回溯來求N後問題的解
//回溯用遞迴來解決
//n表當前行是第n行
static void solveQueen(int n){
//對於每一行需要判斷當前行的每一列
for(int i=0;i<N;i++){
//放置皇后
queen[n]=i; //迴圈賦值給列
//如果當前位置可以放置皇后
if(isPlace(n)==true){
//如果是最後一行,那麼就輸出當前的一個解
if(n==N-1){
//輸出解
sum++;
showResult();
}
//如果不是最後一行,並且當前位置可以放置,那麼就繼續到下一行
else{
solveQueen(n+1); //遞迴到下一行
}
}
//如果當前行的當前列不能放置,那麼就直接迴圈到下一列,不需要寫else
}
}

static void showResult(){
System.out.print("結果"+sum+" ");
for(int i=0;i<N;i++){
System.out.print("("+i+","+queen[i]+")");
System.out.print(" ");
}
System.out.println();
}


}