2n皇后--回溯與遞歸

package new50;

import java.util.Scanner;

public class queen {
static int count;
static int n;
static int[][] a;
public static void main(String[] args) {
Scanner Scan=new Scanner(System.in);
while(Scan.hasNext()){
count=0;
n=Scan.nextInt();
a=new int[n][n];
for(int i=0;i<=n-1;i++)
for(int j=0;j<=n-1;j++)
a[i][j]=Scan.nextInt();
detect(0,2);//從第一行開始查找,先進行填充2
System.out.println(count);
}
}

static void detect(int i,int x){
if(i== n){
if(x==2) detect(0,3);//2的填充完成時,開始填充3
else count++;//每次3的填充完成時,表示一種2n皇后位置被找到
return;//每次一種2n皇后位置count+1後,返回到最後一個3的位置,將其置爲1,並檢驗這個3所在的行的後面的位置能否有
//其他的可能,再依次向上return,若可以再次找到一組完整的3(這個過程將會一直回溯,直到第一行中3可以存在的位置被全部return),
//則count再次+1,否則將return到上一組(已被count記數過的)完整的2的最後一個2,並將最後一個2設爲1,開始尋找這一行中是否存在
//其他可以滿足情況的2,若不能,將依次向上一行回溯,直到將第一行的2所有的位置都進行一次嘗試(到第一行最後一個可放2的位置時,
//若還是找不到一組完整的2,則無法進行遞歸,而此時在尋找的是第一行的2,即第一層函數,無法進行遞歸導致return,返回到main函數中,完成全部可能性的返回)
//若直到從第一行找2的所有可能性回溯結束前找到另一組完整的2,則進行–開始填充新的一組3的嘗試。。
}
for(int j=0;j<=n-1;j++){
if(a[i][j]!=1) continue;//不爲1,放棄此次填充
if(check(i,j,x)) a[i][j]=x;//返回true,則可以填充。
else continue;//不滿足條件,放棄此次填充
detect(i+1,x);//查找下一行可以填充的x的位置
a[i][j]=1;//key factor,有2個作用,1—用於回溯,當下一行沒有出現一個滿足條件的位置時,遞歸的函數一直return到這裏,
//然後把這個位置重新置爲1,以便於進行此次for循環,在這一行的後一符合條件位置置爲x。 2—當完整的一個count查找到時,
//count++;下面緊鄰的return會返回到這裏,用於將符合條件的最後一個3置爲1,以便於查找操作繼續進行,查找下一組符合條件的count。
}
return;
}

static boolean check(int x,int y,int key){
for(int i=0;i<=x-1;i++)
if(a[i][y]==key)
return false;//豎列判斷
for(int i=x-1,j=y-1;i>=0&&j>=0;i–,j–)
if(a[i][j]==key)
return false;//向左上方判斷

  for(int i=x-1,j=y+1;i>=0&&j<=n-1;i--,j++)
	  if(a[i][j]==key)
		  return false;//向右上方判斷
  
  //由於detect方法中的for循環是將在每一行的某一個位置被確定後,進行的遞歸,而每次
  //遞歸所做的對這某一個位置的所有嘗試進行一遍後,失敗--則立即將這個位置回溯爲1,並開始嘗試這一行剩下的符合x的位置
  //--所以不會出現一行有2個x,所以不需行判斷,若  成功---則依着這個位置繼續向下遞歸,直到完成count+1,成功後回到detect中的註釋,仍然會不會出現過
  //一行中出現2個x,所以不需行判斷
  
  return true;//此位置符合條件,返回true。

}

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章