回溯(Back Tracking)

回溯(Back Tracking)

  • 回溯可以理解为:通过选择不同的岔路口来通往目的地(找到想要的结果)
    每一步都选择一条路出发,能进则进,不能进则退回上一步(回溯),换一条路再试
  • 树、图的深度优先搜索(DFS)、八皇后、走迷宫都是典型的回溯应用
    回溯(Back Tracking)_第1张图片
  • 不难看出来,回溯很适合使用递归

练习 – 八皇后问题(Eight Queens)

  • 八皇后问题是一个古老而著名的问题
  • 在8x8格的国际象棋上摆放八个皇后,使其不能互相攻击:任意两个皇后都不能处于同一行、同一列、同一斜线上
  • 请问有多少种摆法?
    回溯(Back Tracking)_第2张图片

(1)八皇后问题的解决思路

  • 思路一:暴力出奇迹
    ①、从 64 个格子中选出任意 8 个格子摆放皇后,检查每一种摆法的可行性
    ②、一共 C648 种摆法(大概是 4.4 ∗ 109 种摆法)
    回溯(Back Tracking)_第3张图片
  • 思路二:根据题意减小暴力程度
    ①、很显然,每一行只能放一个皇后,所以共有 88 种摆法(16777216 种),检查每一种摆法的可行性
  • 思路三:回溯法
    ①、回溯 + 剪枝

(2)四皇后 – 回溯法

  • 在解决八皇后问题之前,可以先缩小数据规模,看看如何解决四皇后问题
    回溯(Back Tracking)_第4张图片

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

回溯(Back Tracking)_第5张图片

(4)八皇后 – 回溯法1

回溯(Back Tracking)_第6张图片
回溯(Back Tracking)_第7张图片

  • 以此类推…

(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("--------------------");
    }
}

你可能感兴趣的:(算法,剪枝,回溯,递归,递归算法)