《Java算法》Java回溯算法


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;
    }
}

來源:https://leetcode-cn.com/problemset/all/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM