八皇后——递归实现

八皇后


题目

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

问题分析
简单的说问题就是,在8×8格的棋盘中要求同行同列同斜线不能有重复的皇后棋子,问多少种摆法。

用递归的方法实现,递归就像找文件一样,一个文件夹下面有若干文件,不确定文件在哪,先找第一个文件夹,第一个文件夹下面还有文件夹,继续往下找,若找不到,则返回上一个文件夹,找同级文件夹内,直到找到,每个文件夹内都是一个for循环。

对于八皇后问题也可以这样考虑,首先初始化棋盘,将棋盘copy一份,在copy的棋盘中操作,先将皇后放在第一行第一个,第二个皇后在第二行中找不冲突的位置放,依次向下放皇后,若位置冲突,则换该行其他格子放。若该行格子都不能放皇后,说明前面皇后放的有问题,删掉上一个皇后,重新考虑上一个皇后位置,依此逻辑,直到找到所有的摆法。
在这里插入图片描述
八皇后递归实现核心代码

public static void eightQueen(int row,int[][] board){
        if(row==8){
            count++;
            System.out.println("第"+count+"种可能");
            print(board);       //打印棋盘
            System.out.println();
        }else{
            int[][] newBoard=copyOf(board);    //拷贝一个蓝本
            for(int col=0;col<8;col++){
                if(isNoDanger(row,col,newBoard)){       //该位置不冲突时
                    for(int c=0;c<8;c++){       //清行代码
                        newBoard[row][c]=0;
                    }
                    newBoard[row][col]=1;               //放皇后
                    eightQueen(row+1,newBoard);    //递归
                }
            }
        }
    }

核心代码解析
第一次进来,row=0,意思是要在第一行摆皇后,只要传进来的row参数不是8,表明还没出结果,那么就进入到for循环里面,copy一个蓝本,进行放置皇后操作,col从0开始,即第一列。此时第一行第一列肯定合乎要求,能放下皇后,因为还没有任何其他皇后来干扰。

若皇后放置也不冲突(isNoDanger方法),在if里面又会调用一下自己(即递归),row加了1,表示摆第二行的皇后了。第二行的皇后在走for循环的时候,分两种情况,

  • 第一种情况:for循环没走到头时就有通过isNoDanger方法的,那么就往下走再调用一下自己(即再往下递归),row再加1(即摆第三行的皇后了,以此类推)。

  • 第二种情况:for循环走到头了都没有通过isNoDanger方法的,说明第二行根本一个皇后都摆不了,也触发不了递归,后面的就不用提了,此时控制第一行皇后位置的for循环col加1,即第一行的皇后往后移一格,然后再往下走,重复上述逻辑。

注意:一定要添加清行的代码,它只有在皇后摆不下去的时候会执行清0的动作(避免脏数据干扰)

这段核心代码的原理弄懂,八皇后问题就很好解决了,八皇后问题一共有92种情况,下面是用Java实现的完整代码:

public class EightQueen {
    static int count=0;   //有多少只可能
    public static void main(String[] args) {
        int[][] board=new int[8][8];
        eightQueen(0,board);
    }
    
    //递归函数
    public static void eightQueen(int row,int[][] board){   
        if(row==8){
            count++;
            System.out.println("第"+count+"种可能");
            print(board);       //打印棋盘
            System.out.println();
        }else{
            int[][] newBoard=copyOf(board);    //拷贝一个蓝本
            for(int col=0;col<8;col++){
                if(isNoDanger(row,col,newBoard)){       //该位置不冲突时
                    for(int c=0;c<8;c++){     
                        newBoard[row][c]=0;
                    }
                    newBoard[row][col]=1;               //放皇后
                    eightQueen(row+1,newBoard);    //递归
                }
            }
        }
    }
    //判断该位置是否与其他皇后冲突
    private static boolean isNoDanger(int row, int col, int[][] newBoard) {
        //向上
        for(int r=row-1;r>=0;r--){
            if(newBoard[r][col]==1){
                return false;
            }
        }
        //向左上
        for(int r=row-1,c=col-1;r>=0&&c>=0;r--,c--){
            if(newBoard[r][c]==1){
                return false;
            }
        }
        //向右上
        for(int r=row-1,c=col+1;r>=0&&c<8;r--,c++){
            if(newBoard[r][c]==1){
                return false;
            }
        }
        return true;
    }

    //复制棋盘
    private static int[][] copyOf(int[][] board) {
        int[][] newBoard=new int[board.length][board.length];
        for(int i=0;i<board.length;i++){
            for(int j=0;j<board[i].length;j++){
                newBoard[i][j]=board[i][j];
            }
        }
        return newBoard;
    }

    //打印棋盘
    private static void print(int[][] board) {
        for(int i=0;i<board.length;i++){
            for(int j=0;j<board[i].length;j++){
                System.out.print(board[i][j]+" ");
            }
            System.out.println();
        }
    }

}

重点是核心代码部分,即递归的思想,递归思想了解清楚,递归类的题就好做很多。

发布了70 篇原创文章 · 获赞 56 · 访问量 1959

猜你喜欢

转载自blog.csdn.net/qq_43624033/article/details/103704888
今日推荐