7.八皇后问题

八皇后问题算法解题思路

1.第一个皇后先放到第一行第一列。

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

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

4.当得到一个正确解时,就开始回溯,北京第一个皇后放在第一列的所有正确解嗯全部拿到。

5.然后开始回头继续第一个皇后放入第二列。,后面继续循环,执行1234步骤。

说明:

  理论上应该创建一个二维数组表示棋盘,但实际上可以通过算法用一个一维数组即可解决问题。

  arr[8]={0,4,7,5,2,6,1,3}对应的arr下标表示第几行,即第几个皇后,arr[i]=val,val表示第i+1个皇后,放在i+1行的第val+1列

package cn.com.linkedList;

/**
 * 8皇后问题
 */
public class EightEmpresses {
    //设置棋盘的规格
    private static final int QUEEN = 8;
    //设置棋盘
    private static final int[][] CHECKERBOARD = new int[QUEEN][QUEEN];
    //第几种解法
    private static int count = 0;

    public static void show() {
        System.out.println("第" + (++count) + "种解法--------");
        for (int i = 0; i < CHECKERBOARD.length; i++) {
            for (int j = 0; j < CHECKERBOARD[i].length; j++) {
                System.out.print(CHECKERBOARD[i][j] + "  ");
            }
            System.out.println();
        }
    }

    /**
     * 检查这个点是否可以存放数据
     * 
     * @param row 行
     * @param col 列
     * @return 是否可以存放数据
     */
    public static boolean check(int row, int col) {
        //1.检查上方是否有皇后
        for (int i = row - 1; i >= 0; i--) {
            if (CHECKERBOARD[i][col] == 1) {
                return false;
            }
        }
        //2.判断左上方是否有值
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (CHECKERBOARD[i][j] == 1) {
                return false;
            }
        }
        //3.判断右上方是否有值
        for (int i = row - 1, j = col + 1; i >= 0 && j <QUEEN; i--, j++) {
            if (CHECKERBOARD[i][j] == 1) {
                return false;
            }
        }
        return true;
    }

    /**
     * 开始从第几行开始放
     *
     * @param row
     */
    public static void put(int row) {
        //1. 从第1行开始放弃,每一列都循环一遍
        for (int i = 0; i < QUEEN; i++) {
            //2. 判断当前位置是否可以存放
            if (check(row, i)) {
                //3. 可以存放,将当前位置置为1
                CHECKERBOARD[row][i]=1;
                //4. 到达最后一行,输出即可!
                if (row==QUEEN-1){
                    show();
                }else{
                    //5. 放下一行,递归,进来又循环一遍所有列
                    put(row+1);
                }
                //重点::这里需要好好理解下,如果发现某个点导致下述的没法放了,就开始回溯,改正之前错误点位置,好好品!
                CHECKERBOARD[row][i]=0;
            }
        }
    }



    public static void main(String[] args) {
        put(0);
    }
}
测试输出:
    第1种解法--------
1  0  0  0  0  0  0  0  
0  0  0  0  1  0  0  0  
0  0  0  0  0  0  0  1  
0  0  0  0  0  1  0  0  
0  0  1  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  1  0  0  0  0  0  0  
0  0  0  1  0  0  0  0  
第2种解法--------
1  0  0  0  0  0  0  0  
0  0  0  0  0  1  0  0  
0  0  0  0  0  0  0  1  
0  0  1  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  0  0  1  0  0  0  0  
0  1  0  0  0  0  0  0  
0  0  0  0  1  0  0  0  
    。。。
    第92种解法--------
0  0  0  0  0  0  0  1  
0  0  0  1  0  0  0  0  
1  0  0  0  0  0  0  0  
0  0  1  0  0  0  0  0  
0  0  0  0  0  1  0  0  
0  1  0  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  0  0  0  1  0  0  0
共计92种解法

 

第二种解法:通过一维数组表示棋盘,如arr[i]=val,表示第i行的第val列是皇后

package cn.com.linkedList;

/**
 * 8皇后问题的第二种解法
 * 只用一个一维数组表示
 * arr[i]=val 表示第i+1行的第val+1位置上放上皇后
 */
public class Queue8 {
    //定义有多少个皇后,即多少行
    private static int max = 8;
    //创建一个一维数组
    private static int[] array = new int[max];
    //第几种解法
    private static int count = 0;

    public static void show() {
        System.out.println("第" + (++count) + "种解法--------");
        for (int i=0;i<array.length;i++){
            System.out.print(array[i]+" ");
        }
        System.out.println("\n--二位棋盘--");
        for (int i=0;i<array.length;i++){
            for (int j=0;j<max;j++){
                if (j==array[i]){
                    System.out.print(1+"  ");
                }else{
                    System.out.print(0+"  ");
                }
            }
            System.out.println();
        }
    }

    /**
     * 放入第几行的皇后
     *
     * @param n
     * @return
     */
    public static boolean check(int n) {
        for (int i = 0; i < n; i++) {
            /*
                这里比较有意思:比较和前几行皇后位置
                    1.比较是否再同一列:array[n] == array[i],同一列的话,这个数值会相等array[n]=val代表第n行的第val列
                    2.判断是否在一条斜线上:
                        这里需要注意的是斜线是45都斜线,即斜率为1,想象去哦盘为一个象限
                        表达式为:y=x+b,线上的两个点
                        1.y1=x1+b
                        2.y2=x2+b
                        1式减2式,发现两个点的y值差等于x值差
                        通过这个特性判断两个点是否在一条斜线上
             */
            if (array[n] == array[i] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
                return false;
            }
        }
        return true;
    }

    public static void put(int row) {
        //这里需要注意,不能是row==max-1,因为当到最后一行时,row==max-1,直接返回了,则下面的赋值就没有进行
        if (row == max) {
            //放到最后一行了,打印输出
            show();
            return;
        }
        //循环i列,每列都循环放一遍
        for (int i = 0; i < max; i++) {
            //这里式回溯的关键点,如果放置了某点,导致下述无法继续放,会回溯到这里i+1,放入到下列,继续下述循环
            array[row] = i;
            //可以放
            if (check(row)) {
                put(row + 1);
            }
        }
    }

    public static void main(String[] args) {
        put(0);
    }
}

测试输出:总计92种解法
    第1种解法--------
0 4 7 5 2 6 1 3 
--二位棋盘--
1  0  0  0  0  0  0  0  
0  0  0  0  1  0  0  0  
0  0  0  0  0  0  0  1  
0  0  0  0  0  1  0  0  
0  0  1  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  1  0  0  0  0  0  0  
0  0  0  1  0  0  0  0  
第2种解法--------
0 5 7 2 6 3 1 4 
--二位棋盘--
1  0  0  0  0  0  0  0  
0  0  0  0  0  1  0  0  
0  0  0  0  0  0  0  1  
0  0  1  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  0  0  1  0  0  0  0  
0  1  0  0  0  0  0  0  
0  0  0  0  1  0  0  0  
    
    。。。
第92种解法--------
7 3 0 2 5 1 6 4 
--二位棋盘--
0  0  0  0  0  0  0  1  
0  0  0  1  0  0  0  0  
1  0  0  0  0  0  0  0  
0  0  1  0  0  0  0  0  
0  0  0  0  0  1  0  0  
0  1  0  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  0  0  0  1  0  0  0  

 

posted @ 2022-11-23 21:35  努力的达子  阅读(73)  评论(0编辑  收藏  举报