回溯(Back Tracking)

兮尹發表於2021-01-01

回溯(Back Tracking)

  • 回溯可以理解為:通過選擇不同的岔路口來通往目的地(找到想要的結果)
    每一步都選擇一條路出發,能進則進,不能進則退回上一步(回溯),換一條路再試
  • 樹、圖的深度優先搜尋(DFS)、八皇后、走迷宮都是典型的回溯應用
    在這裡插入圖片描述
  • 不難看出來,回溯很適合使用遞迴

練習 – 八皇后問題(Eight Queens)

  • 八皇后問題是一個古老而著名的問題
  • 在8x8格的國際象棋上擺放八個皇后,使其不能互相攻擊:任意兩個皇后都不能處於同一行、同一列、同一斜線上
  • 請問有多少種擺法?
    在這裡插入圖片描述

(1)八皇后問題的解決思路

  • 思路一:暴力出奇跡
    ①、從 64 個格子中選出任意 8 個格子擺放皇后,檢查每一種擺法的可行性
    ②、一共 C648 種擺法(大概是 4.4 ∗ 109 種擺法)
    在這裡插入圖片描述
  • 思路二:根據題意減小暴力程度
    ①、很顯然,每一行只能放一個皇后,所以共有 88 種擺法(16777216 種),檢查每一種擺法的可行性
  • 思路三:回溯法
    ①、回溯 + 剪枝

(2)四皇后 – 回溯法

  • 在解決八皇后問題之前,可以先縮小資料規模,看看如何解決四皇后問題
    在這裡插入圖片描述

(3)四皇后 – 剪枝(Pruning)

在這裡插入圖片描述

(4)八皇后 – 回溯法1

在這裡插入圖片描述
在這裡插入圖片描述

  • 以此類推…

(5)八皇后實現 – 合法性檢查

public class Main {
    public static void main(String[] args) {
        new Main().placeQueens(8);
    }

    /**
     * 陣列索引是行號,陣列元素是列號 cols[row] = col
     */
    int[] cols;
    /**
     * 一共有多少種擺法
     */
    int ways;

    void placeQueens(int n) {
        if (n < 1) return;
        cols = new int[n];
        place(0);
        System.out.println(n+"皇后一共有"+ways+"種擺法");
    }

    /**
     * 從第row行開始擺放皇后
     *
     * @param row
     */
    void place(int row) {
        if (row == cols.length){
            ways++;
            show();
            return;
        }

        for (int col = 0; col < cols.length; col++) {
            if (isValid(row,col)){
                //在第row行第col列擺放皇后
                cols[row] = col;
                place(row+1);
                //回溯
            }

        }
    }

    /**
     * 判斷第row行第col列是否可以擺放皇后
     */
    boolean isValid(int row,int col){
        for (int i = 0; i < row; i++) {
            //第col列已經有皇后
            if (cols[i] == col) return false;
            //第i行的皇后跟第row行第col列格子處在同一斜線上
            if ((row - i) == Math.abs(col - cols[i])) return false;
        }
        return true;
    }
	//列印輸出,0代表沒有皇后,1代表有皇后
    void show(){
        for (int row = 0; row < cols.length; row++) {
            for (int col = 0; col < cols.length; col++) {
                if (cols[row] == col){
                    System.out.print("1 ");
                }else {
                    System.out.print("0 ");
                }
            }
            System.out.println();
        }
        System.out.println("--------------------");
    }
}

相關文章