数据结构(JAVA)—— 递归(八皇后问题-回溯算法)

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法

数据结构(JAVA)—— 递归(八皇后问题-回溯算法)_第1张图片

思路分析

1)第一个皇后先放第一行第一列

2)第二个皇后放在第二行第一列、然后判断是否OK, 如果不OK,继续放在第二列、第三列、依次把所有列都放完,找到一个合适

3)继续第三个皇后,还是第一列、第二列……直到第8个皇后也能放在一个不冲突的位置,算是找到了一个正确解

4)当得到一个正确解时,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放到第一列的所有正确解,全部得到.

5)然后回头继续第一个皇后放第二列,后面继续循环执行 1,2,3,4的步骤

说明:理论上应该创建一个二维数组来表示棋盘,但是实际上可以通过算法,用一个一维数组即可解决问题. arr[8] = {0 , 4, 7, 5, 2, 6, 1, 3} //对应arr 下标 表示第几行,即第几个皇后,arr[i] = val , val 表示第i+1个皇后,放在第i+1行的第val+1

代码实现:

package com.sanjin.study;

/**
 * @author sanjin
 * @create 2021-12-21 14:21
 */
public class Queue8 {
    //定义一个max表示有多少皇后
    int max = 8;
    //统计有多少种解法
    static int count = 0;
    //定义数组array,保存皇后放置位置的结果,如arr[8] = {0 , 4, 7, 5, 2, 6, 1, 3}
    int[] array = new int[max];

    public static void main(String[] args) {
        Queue8 queue8 = new Queue8();
        queue8.check(0);
        System.out.println("一种有" + count + "解法");
    }
    //编写放置第n个皇后的方法
    private void check(int n){
        if (n == max){//此时要放第9个皇后,即代表前面8个皇后已经放好了
            print();
        }

        //依次放入皇后,并判断是否冲突
        for (int i = 0; i < max; i++) {
            //先把当前这个皇后n,放在该行的第1列
            array[n] = i;
            //判断放置第n个皇后到i列时,是否冲突
            if (judge(n)){//不冲突
                //接着放第n+1个皇后,即开始递归
                check(n + 1);
            }
            //如果冲突,就继续执行array[n]=i,即将第n个皇后放置在本行的后移一位
        }
    }
    //当放置第n个皇后时,查看是否与前面已摆放的皇后冲突
    private boolean judge(int n){
        for (int i = 0; i < n; i++) {
            //1.array[i] == array[n]判断第n个皇后是否跟前面n-1个在同一列
            //2.Math.abs(n - 1) == Math.abs(array[n] - array[i])判断第n个皇后是否跟前面n-1个在同一斜线
            //3.n每次都在递增,没必要判断是否在同一行
            if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])){
                return false;
            }
        }
        return true;
    }
    //写一个方法,可以将皇后摆放的位置打印出来
    private void print(){
        count++;
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "\t");
        }
        System.out.println();
    }
}

不得不说这个思路蛮好理解的,就类似于穷举,第一个放在第一列的所有情况列出来,再放到第二列,再列出所有情况,这样循环下去。

但是这代码我是真的难理解,感觉时间复杂度不低,需要判断的次数也很多,而且老师用的是一维数组表示棋盘,在理解上也有一些难。

困了我先趴会,醒了之后找一找有没有其他老师的解法。

俺回来了。

讲真的,自己敲了两个小时都没把二维数组实现敲明白,思路自己都有,就是不知道怎么用代码表达,而且定义了很多变量,像什么i,j,row,col,搞得我都有点混了。

最终,请教了我亲爱的鸭子哥。我奇臭无比的代码,经他手以后,散发出理性的光芒。

代码附上:

package com.sanjin.exer;

/**
 * @author sanjin
 * @create 2021-12-21 15:48
 */
public class Queue8 {
    int queueNum = 8;//皇后的数量
    int[][] array = new int[queueNum][queueNum];//创建8*8的棋盘
    static int COUNT = 0;//解決方案的个数
    public static void main(String[] args) {
        Queue8 queue8 = new Queue8();
        queue8.put(0);
        System.out.println("解决方法一共有" + COUNT + "种");
    }
    //放置皇后,并判断
    public void put(int column){
        if (column == queueNum){
            COUNT++;
            show();
            return;
        }
        for (int i = 0; i < queueNum; i++) {
            if (check(i,column)){
                array[i][column] = 1;
                put(column + 1);
                array[i][column] = 0;
            }
        }
    }

    /**判断当前位置是否能放皇后
     * @param row 行数
     * @param col 列数
     * @return 能否放置
     */
    public boolean check(int row,int col){
        for (int i = 0;i < queueNum;i++){
            for (int j = 0; j < queueNum; j++) {
                if (row == i && col == j){
                    continue;
                }
                //同一列有皇后
                if (array[i][col] == 1){
                    return false;
                }
                //同一行有皇后
                if (array[row][j] == 1){
                    return false;
                }
                //对角线有皇后
                if (Math.abs(row - i) == Math.abs(col - j) && array[i][j] == 1){
                    return false;
                }
            }
        }
        return true;
    }

    //打印棋盘
    public void show(){
        System.out.println("第" + COUNT + "方法为:");
        for (int i = 0; i < queueNum; i++) {
            for (int j = 0; j < queueNum; j++) {
                System.out.print(array[i][j] + "\t");
            }
            System.out.println();
        }
    }
}

输出结果图:

数据结构(JAVA)—— 递归(八皇后问题-回溯算法)_第2张图片

不仅如此,鸭子哥对我进行了谆谆教导

数据结构(JAVA)—— 递归(八皇后问题-回溯算法)_第3张图片

我拿到跑成功的代码以后,copy到word里面打印下来,自己划了两个小时,还是没看明白。

比如我不懂check()里面为啥要判断row==i&&col==j

我不懂put()里面的colu是啥意思

我不懂put()里面为啥要array[i][colum]=0

给我整emo了,很希望得到解答。等等再找找视频,看看别人的思路吧。

鸭子哥仍给予我厚望:

数据结构(JAVA)—— 递归(八皇后问题-回溯算法)_第4张图片

并且嘱托我:

 数据结构(JAVA)—— 递归(八皇后问题-回溯算法)_第5张图片

OK,我继续emo,找视频,看思路。

希望有一天,我可以做出来鸭子哥给我的思考题。 

最后再bb一句,我打算听鸭子哥的话了

数据结构(JAVA)—— 递归(八皇后问题-回溯算法)_第6张图片

so明天开始继续赶进度,毕竟我只看了遍java基础,也就只是看了一遍。

你可能感兴趣的:(数据结构,算法,java)