09.递归、递归回溯--迷宫问题、八皇后问题


/**
 * 递归规则:
 * - 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
 * - 方法的局部变量是独立的,不会相互影响, 比如n变量如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据.
 * - 递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError)
 * - 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。
 */
public class Factorial {
    //阶乘
    public static int factorial(int n) {
        if (n == 1) {
            return 1;
        } else {
            return factorial(n - 1) * n;
        }
    }

    //递归打印
    public static void test(int n) {
        if (n > 2) {
            test(n - 1);
        }
        System.out.println("n=" + n);
    }

    public static void main(String[] args) {
        test(4);
        //n=2
        //n=3
        //n=4
        System.out.println("factorial(2) = " + factorial(2));
    }
}
package stu;

/**
 * 递归回溯--迷宫问题
 */
public class MiGong {
    /**
     * 地图,1表示墙,0表示该点没走过
     * 走迷宫方法下->右->上->左
     */
    public static int[][] getMap(){
        int[][] map = new int[8][7];
        int row = map.length;//行数
        int col = map[0].length;//列数
        for (int i = 0; i < row; i++) {
            map[i][0] = 1;
            map[i][col-1] = 1;
        }
        for (int i = 0; i < col; i++) {
            map[0][i] = 1;
            map[row-1][i] = 1;
        }
        return map;
    }
    public static void showMap(int[][] map){
        System.out.println("------map-----");
        int row = map.length;
        int col = map[0].length;
        //打印行号
        for (int i = 0; i < col; i++) {
            if (i==0){
                System.out.print("\t"+i+"\t");
            } else{
                System.out.print(i+"\t");
            }
        }
        System.out.println();
        for (int i = 0; i < row; i++) {
            //打印列号
            System.out.print(i+"\t");
            for (int j = 0; j < col; j++) {
                System.out.print(console(map[i][j])+"\t");
            }
            System.out.println();
        }
        System.out.println("--------------");
    }
    public static String console(int i) {
        if (i == 0) {//未走的点
            return "○";
        } else if (i == 1) {//墙
            return "♟";
        } else if (i == 2) {//已走的点
            return "☻";
        } else if (i == 3) {//死路
            return "×";
        }
        return "×";
    }
    /**
     * 寻路 终点[6][5]
     * 2表示通路走过,3表示该点走过又一次走,变死路了,走不通
     * @param map
     * @param i 横
     * @param j 枞
     * @return
     */
    public static boolean setWay(int[][] map,int i,int j){
        if (map[6][5]==2){
            return true;
        }else {
            if (map[i][j]==0){
                map[i][j]=2;
                if (setWay(map,i+1,j)){//向下
                    return true;
                }else if (setWay(map,i,j+1)){//向右
                    return true;
                }else if (setWay(map,i-1,j)){//向上
                    return true;
                }else if (setWay(map,i,j-1)){//向左
                    return true;
                }else {
                    map[i][j]=3;
                    return false;
                }
            }else { //遇到墙,或死路,或已经走过
                return false;
            }
        }
    }
    public static void main(String[] args){
        int[][] map = getMap();
        showMap(map);
        //从[1][1]做起点
        setWay(map,1,1);
        showMap(map);
        //	0	1	2	3	4	5	6
        //0	♟	♟	♟	♟	♟	♟	♟
        //1	♟	☻	○	○	○	○	♟
        //2	♟	☻	○	○	○	○	♟
        //3	♟	☻	○	○	○	○	♟
        //4	♟	☻	○	○	○	○	♟
        //5	♟	☻	○	○	○	○	♟
        //6	♟	☻	☻	☻	☻	☻	♟
        //7	♟	♟	♟	♟	♟	♟	♟
    }
}
package stu;

/**
 * 八皇后问题:
 * 在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,
 * 即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
 * 八皇后问题算法思路分析:
 * 1.第一个皇后先放第一行第一列
 * 2.第二个皇后放在第二行第一列、然后判断是否OK, 如果不OK,继续放在第二列、第三列、依次把所有列都放完,找到一个合适
 * 3.继续第三个皇后,还是第一列、第二列……直到第8个皇后也能放在一个不冲突的位置,算是找到了一个正确解
 * 4.当得到一个正确解时,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放到第一列的所有正确解,全部得到.
 * 5.然后回头继续第一个皇后放第二列,后面继续循环执行 1,2,3,4的步骤
 */
public class Queens8 {
    private int MAX = 8;
    private static int count = 0;
    private static int judgeCount = 0;
    //第0行的列的位置,默认【0,0】
    private int firstCol = 0;
    //对应arr下标表示第几行,即第几个皇后
    //arr[i] = val , val 表示第i个皇后,放在第i行的第val列,皇后从0到7共8个,行与列也是从0开始
    int[] arr = new int[MAX];

    private boolean queens8 = false;
    private boolean queens82 = false;

    public Queens8() {
        queens8 = true;
        new Queens().check(0);
    }

    public Queens8(int firstCol) {
        queens82 = true;
        this.firstCol = firstCol;
        new Queens().checkByFirstCol(0);
    }

    private class Queens {
        //第n个皇后
        private void check(int n) {
            //1种方法输出一次
            if (n == MAX) {
                console();
                return;
            }
            for (int i = 0; i < MAX; i++) {
                arr[n] = i;
                if (judge(n)) {
                    check(n + 1);
                }
            }
        }

        //按照第n个皇后在第0行的列的位置
        private void checkByFirstCol(int n) {
            //1种方法输出一次
            if (n == MAX) {
                console();
                return;
            }
            for (int i = 0; i < MAX; i++) {
                if (n == 0 && i > firstCol) {
                    break;
                }
                if (n == 0 && i != firstCol) {
                    continue;
                }
                arr[n] = i;
                if (judge(n)) {
                    check(n + 1);
                }
            }
        }

        //判断是否冲突
        //第n个皇后
        private boolean judge(int n) {
            judgeCount++;
            for (int i = 0; i < n; i++) {
                //第n个是否与前面的n-1在同一列
                //第n个是否与第i个是否在同一斜线(两个的行差等于列差)
                if (arr[n] == arr[i] || Math.abs(n - i) == Math.abs(arr[n] - arr[i])) {
                    return false;
                }
            }
            return true;
        }
    }

    //输出位置
    private void console() {
        count++;
        for (int i : arr) {
            System.out.print(i + "\t");
        }
        System.out.println();
    }

    private void print() {
        if (queens8){
            System.out.println("共有" + count + "种解法");
        }else {
            System.out.println("第0列的皇后放在第"+firstCol+"列,有" + count + "种解法");
        }
        System.out.println("判断冲突次数:" + judgeCount);
    }

    public static void main(String[] args) {
        new Queens8().print();
        new Queens8(0).print();
        new Queens8(1).print();
    }
    //0	4	7	5	2	6	1	3	
    //0	5	7	2	6	3	1	4	
    //0	6	3	5	7	1	4	2	
    //0	6	4	7	1	3	5	2	
    //1	3	5	7	2	0	6	4	
    //1	4	6	0	2	7	5	3	
    //1	4	6	3	0	7	5	2	
    //1	5	0	6	3	7	2	4	
    //1	5	7	2	0	3	6	4	
    //1	6	2	5	7	4	0	3	
    //1	6	4	7	0	3	5	2	
    //1	7	5	0	2	4	6	3	
    //2	0	6	4	7	1	3	5	
    //2	4	1	7	0	6	3	5	
    //2	4	1	7	5	3	6	0	
    //2	4	6	0	3	1	7	5	
    //2	4	7	3	0	6	1	5	
    //2	5	1	4	7	0	6	3	
    //2	5	1	6	0	3	7	4	
    //2	5	1	6	4	0	7	3	
    //2	5	3	0	7	4	6	1	
    //2	5	3	1	7	4	6	0	
    //2	5	7	0	3	6	4	1	
    //2	5	7	0	4	6	1	3	
    //2	5	7	1	3	0	6	4	
    //2	6	1	7	4	0	3	5	
    //2	6	1	7	5	3	0	4	
    //2	7	3	6	0	5	1	4	
    //3	0	4	7	1	6	2	5	
    //3	0	4	7	5	2	6	1	
    //3	1	4	7	5	0	2	6	
    //3	1	6	2	5	7	0	4	
    //3	1	6	2	5	7	4	0	
    //3	1	6	4	0	7	5	2	
    //3	1	7	4	6	0	2	5	
    //3	1	7	5	0	2	4	6	
    //3	5	0	4	1	7	2	6	
    //3	5	7	1	6	0	2	4	
    //3	5	7	2	0	6	4	1	
    //3	6	0	7	4	1	5	2	
    //3	6	2	7	1	4	0	5	
    //3	6	4	1	5	0	2	7	
    //3	6	4	2	0	5	7	1	
    //3	7	0	2	5	1	6	4	
    //3	7	0	4	6	1	5	2	
    //3	7	4	2	0	6	1	5	
    //4	0	3	5	7	1	6	2	
    //4	0	7	3	1	6	2	5	
    //4	0	7	5	2	6	1	3	
    //4	1	3	5	7	2	0	6	
    //4	1	3	6	2	7	5	0	
    //4	1	5	0	6	3	7	2	
    //4	1	7	0	3	6	2	5	
    //4	2	0	5	7	1	3	6	
    //4	2	0	6	1	7	5	3	
    //4	2	7	3	6	0	5	1	
    //4	6	0	2	7	5	3	1	
    //4	6	0	3	1	7	5	2	
    //4	6	1	3	7	0	2	5	
    //4	6	1	5	2	0	3	7	
    //4	6	1	5	2	0	7	3	
    //4	6	3	0	2	7	5	1	
    //4	7	3	0	2	5	1	6	
    //4	7	3	0	6	1	5	2	
    //5	0	4	1	7	2	6	3	
    //5	1	6	0	2	4	7	3	
    //5	1	6	0	3	7	4	2	
    //5	2	0	6	4	7	1	3	
    //5	2	0	7	3	1	6	4	
    //5	2	0	7	4	1	3	6	
    //5	2	4	6	0	3	1	7	
    //5	2	4	7	0	3	1	6	
    //5	2	6	1	3	7	0	4	
    //5	2	6	1	7	4	0	3	
    //5	2	6	3	0	7	1	4	
    //5	3	0	4	7	1	6	2	
    //5	3	1	7	4	6	0	2	
    //5	3	6	0	2	4	1	7	
    //5	3	6	0	7	1	4	2	
    //5	7	1	3	0	6	4	2	
    //6	0	2	7	5	3	1	4	
    //6	1	3	0	7	4	2	5	
    //6	1	5	2	0	3	7	4	
    //6	2	0	5	7	4	1	3	
    //6	2	7	1	4	0	5	3	
    //6	3	1	4	7	0	2	5	
    //6	3	1	7	5	0	2	4	
    //6	4	2	0	5	7	1	3	
    //7	1	3	0	6	4	2	5	
    //7	1	4	2	0	6	3	5	
    //7	2	0	5	1	4	6	3	
    //7	3	0	2	5	1	6	4	
    //共有92种解法
    //判断冲突次数:15720
    //0	4	7	5	2	6	1	3	
    //0	5	7	2	6	3	1	4	
    //0	6	3	5	7	1	4	2	
    //0	6	4	7	1	3	5	2	
    //第0列的皇后放在第0列,有96种解法
    //判断冲突次数:17505
    //1	3	5	7	2	0	6	4	
    //1	4	6	0	2	7	5	3	
    //1	4	6	3	0	7	5	2	
    //1	5	0	6	3	7	2	4	
    //1	5	7	2	0	3	6	4	
    //1	6	2	5	7	4	0	3	
    //1	6	4	7	0	3	5	2	
    //1	7	5	0	2	4	6	3	
    //第0列的皇后放在第1列,有104种解法
    //判断冲突次数:19562
}
posted @ 2019-10-10 16:04  fly_bk  阅读(197)  评论(0编辑  收藏  举报