7.递归回溯问题经典案例迷宫问题和八皇后

迷宫问题

核心思路在于递归线路选择

/**
 * 约定迷宫的出口是row,column 即右下角的那个点
 * 约定数字1为墙,2为走过的路,3为死路,0表示没有走过
 */
public class MazeDemo {
    final int x;
    final int y;
    int[][] maze;

    public MazeDemo(int x, int y) {
        this.x = x;
        this.y = y;
        initMaze();
    }

    public void initMaze() {
        int[][] maze = new int[x][y];
        for (int i = 0; i < x; i++) {
            maze[i][0] = 1;
            maze[i][y - 1] = 1;
        }

        for (int i = 0; i < y; i++) {
            maze[0][i] = 1;
            maze[x - 1][i] = 1;
        }
        this.maze = maze;
    }

    public void print() {
        for (int[] x : maze) {
            for (int y : x) {
                System.out.print(y + "\t");
            }
            System.out.println();
        }
    }

    public void setBlock(final int row, final int column) {
        maze[row][column] = 1;
    }

    /**
     * 起点位置  左上方顶点 坐标
     * 移动策略默认采用 ↓ → ↑ ←
     *
     * @param x
     * @param y
     */
    public boolean passMaze(final int x, final int y) {
        if (maze[this.x - 2][this.y - 2] == 2) {
            // 最后出口走到了退出
            return true;
        } else {
            // 没走过
            if (maze[x][y] == 0) {
                maze[x][y] = 2;
                if (passMaze(x + 1, y)) {
                    //向下走
                    return true;
                } else if (passMaze(x, y + 1)) {
                    // 向右走
                    return true;
                } else if (passMaze(x - 1, y)) {
                    // 向上走
                    return true;
                } else if (passMaze(x, y - 1)) {
                    // 向左走
                    return true;
                } else {
                    // 上下左右都走不通
                    maze[x][y] = 3;
                    return false;
                }
            }
            return false;
        }
    }


    public static void main(String[] args) {
        MazeDemo mazeDemo = new MazeDemo(7, 8);
        mazeDemo.setBlock(3, 1);
        mazeDemo.setBlock(3, 2);
        mazeDemo.print();
        mazeDemo.passMaze(1, 1);
        System.out.println("===============");
        mazeDemo.print();
    }
}

八皇后问题

核心算法在于如何判断是否在同一行的算法solution[i] == solution[n]

判断是否在同一斜线的算法 当前皇后和老皇后的行差值和当前皇后和老皇后的列差值是否相等

Math.abs(n-i)==Math.abs(solution[n]-solution[i])

// 用一个一维数组表示八皇后问题的一种解法 数组的index 为第index排的皇后 值为皇后在这排摆放的位置
// 如arr[0,5,7,3,4,5,6,7]为第1排皇后摆第一排第1列,第2个皇后摆在第2第5+1列,第3个皇后摆在第排7+1列...
public class Queen8 {

    public final int max = 8;

    static int count = 0;

    // 一种解决方案
    public int[] solution = new int[max];

    public void print() {
        System.out.println(Arrays.toString(solution));
    }

    /**
     * 摆放棋子
     * n表示摆放第几个皇后
     */
    public void putQueen(int n) {
        if (n == max) {
            // 摆放最后一个皇后的下一个皇后了说明已经摆放完毕
            count++;

            print();
            return;
        }
        // 从第n行第一列开始尝试摆放
        for (int i = 0; i < max; i++) {
            // 将当前这个第n个皇后 依次尝试摆放到0-8所有的位置
            solution[n] = i;
            // 摆好了之后 solution[n] = i 已经完成了复制 再调用check方法
            if (check(n)) { // 如果不冲突的话 就继续放下一个即下一排皇后开始递归
                putQueen(n + 1);
            }
        }
    }

    /**
     * 检查第N行的皇后是否跟之前的皇后冲突
     * false表示冲突 true表示不冲突
     *
     * @param n
     * @return
     */
    public boolean check(int n) {
        // 判断之前摆放的棋子是否在同一行同一列
        for (int i = 0; i < n; i++) {
            // solution[i] == solution[n] 判断之前的所有棋子是否同一列
            // solution[i]就表示第i个皇后的位置是solution[i] solution[n]表示当前这一行n的摆放的列位置 从第1行开始一直循环判断往上判断
            // 如果发现有重复的说明之前有棋子摆放在了同一列 直接返回false
            // Math.abs(n - i) == Math.abs(solution[n] - solution[i]
            // 当前皇后和老皇后的差,如果等于 他们位置的差,就表明在同一斜线
            // Math.abs(n-i) n 当前皇后 i之前摆好的皇后
            // Math.abs(solution[n] - solution[i]) 当前皇后位置 - 老皇后的位置
            if (solution[i] == solution[n] || Math.abs(n - i) == Math.abs(solution[n] - solution[i])) {
                return false;
            }
        }
        return true;
    }


    public static void main(String[] args) {
        Queen8 queen8 = new Queen8();
        // 从第一排开始
        queen8.putQueen(0);
        System.out.println(count);

    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值