DFS解決n皇后問題
問題描述
在nxn格的棋盤上放置彼此不受攻擊的n個皇后。按照國際象棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。n皇后問題等價於在nxn格的棋盤上放置n個皇后,任何2個皇后不放在同一行或同一類或同一斜線上。
演算法設計
用n元組x[1:n]表示n皇后問題的解。其中x[i]表示皇后i放在棋盤的第i行,x[i]列。由於不允許將2個皇后放在同一列,所以解向量中的x[i]互不相同。2個皇后不能放置在同一斜線上市問題的隱約束。將nxn棋盤看作二維方陣,行號從上到下1,2....n,,列號從左到右依次編號為1,2....n。斜率為-1的直線上,兩個下標差行號-列號值相等,同理,斜率為+1的斜線上,兩個下標的和(行號+列號)值相等。因此只要|i-k|=|j-l|成立,就表明兩個皇后位於同一條斜線上,問題的隱約束化成了顯約束。
用回溯法解n皇后問題時,用完全n叉樹表示解空間。可行性約束place減去不滿足行列和斜線約束的子樹。
搜尋過程程式碼如下:
import java.util.Scanner;
import java.util.Arrays;
class NQueen //一個工具類
{
static int n; //皇后個數
static int []x;//當前解
static long sum;//當前已找到的可行方案數
public static long nQueen(int nn)
{
n=nn;
sum=0;
x=new int[n+1]; //x[0]不用,0下標在計算時比較繁瑣,所以從1下標開始用根據棋盤標號。
for (int i=0; i<=n;i++ ) //賦初值0,初始化操作
{
x[i]=0;
}
backtrack(1);
return sum;
}
private static boolean place(int k)//判斷當前放置的皇后是否滿足條件。與已經搜尋到的(k-1)個皇后進行比較
{
for(int j=1;j<k;j++)
if((Math.abs(k-j)==Math.abs(x[j]-x[k]))||(x[j]==x[k]))
return false; //不滿足條件,則返回false
return true; //滿足條件返回true
}
private static void backtrack(int t) //t表示當前搜尋的層數,注意該部分的構造
{
if(t>n)
{
sum++;
System.out.println(Arrays.toString(x));
} //t>n表示得到了n皇后的一組放置方法
else
for(int i=1;i<=n;i++) //對t層上的每個節點進行搜尋
{
x[t]=i;
if(place(t))backtrack(t+1);
}
}
}
class NQueenTest
{
public static void main(String[] args)
{
System.out.print("請輸入皇后的個數:");
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
long result=0;
result=NQueen.nQueen(n);
System.out.println("");
System.out.println("方案數:"+result);
sc.close();
}
}
總結:
1.注意類的建立,該類是一個解決該問題的一個工具類。
2.本題中的搜尋過程較為明確,較簡單。
3.將判斷方法封裝在一個成員函式中,符合結構化的設計思想。
4.注意解決問題的過程中,各個引數的確定。陣列中儲存當前解。