1. 概要
回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。許多復雜的,規模較大的問題都可以使用回溯法,有“通用解題方法”的美稱。
2. 原理
我們通過皇后問題來講解回溯算法。
回溯算法經典案例皇后問題:
n 皇后問題研究的是如何將 n 個皇后放置在 n×n 的棋盤上,並且使皇后彼此之間不能相互攻擊。
給定一個整數 n,返回所有不同的n皇后問題的解決方案。
每一種解法包含一個明確的n 皇后問題的棋子放置方案,該方案中 'Q' 和 '.' 分別代表了皇后和空位。
示例: 輸入: 4
// 解法 1 // 解法 2
解釋: 4 皇后問題存在兩個不同的解法。
回溯算法原理圖解:
如何判斷皇后是否會被攻擊: 橫排,豎排好判斷,對角線如何判斷
根據圖解找到對角線規律。
3 代碼:
import java.util.ArrayList; import java.util.List; public class Subject98 { //豎排被占登記,用於判斷是否能夠被豎排攻擊 int rows[]; // // "從左到右對角線" 登記,用於判斷是否能夠被豎排攻擊 int hills[]; // "從右到左對角線" 登記,用於判斷是否能夠被豎排攻擊 int dales[]; int n; // output List<List<String>> output = new ArrayList(); // 皇后的位置 int queens[]; public static void main(String[] args) { List<List<String>> listList = new Subject98().solveNQueens(6); System.out.println(listList); } /** * 判斷該位置是否會被攻擊 * @param row * @param col * @return */ public boolean isNotUnderAttack(int row, int col) { int res = rows[col] + hills[row - col + n - 1] + dales[row + col]; return (res == 0) ? true : false; } /** * 將皇后放入該位置 * @param row * @param col */ public void placeQueen(int row, int col) { queens[row] = col; //將皇后位置放入 rows[col] = 1; //豎排攻擊位置 hills[row - col + n - 1] = 1; // "從左到右對角線" 攻擊位置 dales[row + col] = 1; //"從右到左對角線" 攻擊位置 } /** * 回溯皇后位置 * @param row * @param col */ public void removeQueen(int row, int col) { queens[row] = 0; rows[col] = 0; hills[row - col + n - 1] = 0; dales[row + col] = 0; } /** * 將滿足條件的皇后位置放入output中 */ public void addSolution() { List<String> solution = new ArrayList<String>(); for (int i = 0; i < n; ++i) { int col = queens[i]; StringBuilder sb = new StringBuilder(); for(int j = 0; j < col; ++j) sb.append("."); sb.append("Q"); for(int j = 0; j < n - col - 1; ++j) sb.append("."); solution.add(sb.toString()); } output.add(solution); } public void backtrack(int row) { for (int col = 0; col < n; col++) { if (isNotUnderAttack(row, col)) { placeQueen(row, col); // 皇后數量是否滿足,滿足則輸出 if (row + 1 == n) addSolution(); // 不滿足則繼續 else backtrack(row + 1); // 回溯。 removeQueen(row, col); } } } public List<List<String>> solveNQueens(int n) { this.n = n; rows = new int[n]; hills = new int[2 * n - 1]; dales = new int[2 * n - 1]; queens = new int[n]; backtrack(0); return output; } }