回溯法
一種選優搜索法,又稱試探法。利用試探性的方法,在包含問題所有解的解空間樹中,將可能的結果搜索一遍,從而獲得滿足條件的解。搜索過程采用深度遍歷策略,並隨時判定結點是否滿足條件要求,滿足要求就繼續向下搜索,若不滿足要求則回溯到上一層,這種解決問題的方法稱為回溯法。
回溯法解求解問題步驟
- 針對給定問題,定義問題的解空間樹;
- 確定易於搜索的解空間結構;
- 以深度優先方式搜索解空間,並且在搜索過程中用剪枝函數避免無效搜索;
- 用回溯法求解問題,重點是設計問題的解空間樹,其解題過程則是深度遍歷解空間樹的過程。
解空間樹
是依據待求解問題的特性,用樹結構表示問題的解結構、用葉子表示問題所有可能的解的一棵樹。
解空間樹的形成過程
我們可以把求解問題的過程當作一系列的決定來考慮,回溯法對每一個決定都系統地分析所有可能的結果。而每一次決定即為解空間樹中的一個分支結點,各種可能的結果便形成了各棵不同的子樹,問題最終所有可能的解將展現在所有的葉子上。這便是解空間樹的形成過程。
對解空間樹的遍歷可搜索到問題所有可能的解,因此,可獲得滿足要求的全部解,也可通過對所有解的比較選擇獲得最優解。
由於空間問題,下面給出一個三皇后問題的解空間樹(3皇后問題無解),樹中第i層的結點決定第i行皇后的擺放位置,均有三種不同的選擇,便形成了三個孩子結點,但其中不包括不符合要求的布局。N皇后問題解空間樹與三皇后問題解空間樹類似。
求解N皇后問題的回溯法
N皇后問題要求求解在N*N的棋盤上放置N個皇后,並使各皇后彼此不受攻擊的所有可能的棋盤布局。皇后彼此不受攻擊的約束條件是:任何兩個皇后均不能在棋盤上同一行、同一列或者同一對角線上出現。
由於N皇后問題不允許兩個皇后在同一行,所以,可用一維數組X表示N皇后問題的解,X[i]表示第i行的皇后所在的列號。例如一個滿足要求的四皇后棋盤布局如下圖所示,其結果X數組的值為:[2, 4, 1, 3]。
由上述X數組求解N皇后問題,保障了任意兩個皇后不在同一行上,而判定皇后彼此不受攻擊的其他條件,可以描述如下:
(1)X[i] = X[s],則第i行與第s行皇后在同一列上。
(2)如果第i行的皇后在第j列,第s行皇后在第t列,即X[i] = j和X[s] = t,則只要i-j = s-t或者i+j = s+t,說明兩個皇后在同一對角線上。
對兩個等式進行變換后,得到結論:只要|i-s| = |j-t|(即i-s = X[i]-X[s]),則皇后在同一對角線上。
解N皇后問題需要遍歷解空間樹,遍歷中要隨時判定當前結點棋盤布局是否符合要求,符合要求則繼續向下遍歷,直至判斷得到一個滿足約束條件的葉子結點,從而獲得一個滿足要求的棋盤布局;不符合要求的結點將被舍棄(稱之為剪枝),並回溯到上一層的結點繼續遍歷。當整棵樹遍歷結束時,已獲得所有滿足要求的棋盤布局。
八皇后問題java實現:
public class Queen { public static int num = 0; // 方案數 public static final int MAXQUEEN = 8; // 皇后數 public static int[] cols = new int[MAXQUEEN]; // 定義數組,表示MAXQUEEN列棋子中皇后擺放位置 /* * @param n:填第n列的皇后 */ public void getCount(int n) { boolean[] rows = new boolean[MAXQUEEN]; for (int m = 0; m < n; m++) { rows[cols[m]] = true; int d = n - m; // 正斜方向 if (cols[m] - d >= 0) { rows[cols[m] - d] = true; } // 反斜方向 if (cols[m] + d <= (MAXQUEEN - 1)) { rows[cols[m] + d] = true; } } for (int i = 0; i < MAXQUEEN; i++) { if (rows[i]) { // 不能放 continue; } cols[n] = i; // 下面仍然有合法位置 if (n < MAXQUEEN - 1) { getCount(n + 1); } else { // 找到完整的一套方案 num++; printQueen(); } } } private void printQueen() { System.out.println("第" + num + "種方案"); for (int i = 0; i < MAXQUEEN; i++) { for (int j = 0; j < MAXQUEEN; j++) { if (i == cols[j]) { System.out.print("0 "); } else { System.out.print("+ "); } } System.out.println(); } } public static void main(String[] args) { Queen queen = new Queen(); queen.getCount(0); } }