八皇后问题,回溯算法带详细注释和打印日志

一、背景

八皇后问题,是由国际象棋棋手马克斯·贝瑟尔于1848年提出的问题,表述为如果在8*8的棋盘上摆放8个皇后,有多少种摆法?

八皇后问题,回溯算法带详细注释和打印日志_第1张图片

皇后是一个强大的NPC,所谓一山不容二虎,一向不容二后,所以摆放的限制规则是这个皇后的横向、纵向、斜向都不能有其他皇后。

这个问题其实是非常难的,数学王子高斯认为有76种解法,只是现在有了计算机,渣渣如我也能算出更多的摆法,八皇后应该是有92种解法。

八皇后问题,回溯算法带详细注释和打印日志_第2张图片

二、解法

这个问题可以使用回溯法来解题,回溯法简单来说就是:

把问题的解空间转变为图或者树的数据结构,然后使用深度优先搜索(DFS)策略遍历,遍历时遇到不符合条件(回溯点)的情况,就退出上一步(回溯)。遍历的过程中按需求记录可用解或者是最优解。

三、代码

代码来自大佬文章:史上最简明八皇后问题分析与套路总结_bitcarmanlee的博客-CSDN博客

文章写得非常好推荐一看,然后我在原有代码基础上改了些变量名,加了代码注释和日志打印,便于学习加深理解,算是锦上添花了哈哈

话不多说,上码

public class NQueen {

    // N个皇后,4打印过程较短直观,改成8就是八皇后
    public static int N = 4;
    // 初始化一个正方形方格
    public static int[][] boards = new int[N][N];
    // 方案个数
    public static int result = 0;
    
    public static void main(String[] args) {
        printBoardDesc();
        printActualBoard();
        
        System.out.println("游戏开始...\n");
        putQueen(0);
        System.out.println("游戏结束,找到方案个数=" + result);
    }

    /**
     * 在某一列放置皇后
     */
    public static void putQueen(int row) {
        if (row == N) {
            // 能走到这里说明棋盘每一行都放了一个棋子并且通过了校验,这就是一个可用答案
            System.out.println("---找到一种方案---");
            printActualBoard();
            result++;
        } else {
            System.out.println("开始在第"+row+"行放棋子");
            // row指定了新的一行,在这一行从头逐列向右扫描,这时每行只填一次,所以check方法内部不用判断同一行是否有其他棋子
            int totalColumn = N;
            for (int column = 0; column < totalColumn; column++) {
                if (check(row, column)) {
                    boards[row][column] = 1;
                    putQueen(row + 1); // 最好的情况是一直递归往下找
                    
                    System.out.println("\n【回溯】此时棋盘内容是");
                    printActualBoardMock(row, column);
                    System.out.println();
                    boards[row][column] = 0; // 找不到需要回溯
                }
            }
        }
    }

    /**
     * 检测当前位置是否可用
     */
    public static boolean check(int row, int column) {
        System.out.println("\n开始检查,当前准备放的位置是("+row+","+column+") 棋盘内容是:");
        printActualBoardMock(row, column);
        
        // 同一列从顶向下检查是否有皇后
        for (int i = 0; i < row; i++) {
            if (boards[i][column] == 1) {
                System.out.println(">>>检查列失败 ("+i+","+column+")位置有棋子");
                return false;
            }
        }
        // 向左上角逐个检查是否有皇后
        for (int m = row - 1, n = column - 1; m >= 0 && n >= 0; m--, n--) {
            if (boards[m][n] == 1) {
                System.out.println(">>>检查左上角失败 ("+m+","+n+")位置有棋子");
                return false;
            }
        }
        // 向右上角逐个检查是否有皇后
        for (int m = row - 1, n = column + 1; m >= 0 && n < N; m--, n++) {
            if (boards[m][n] == 1) {
                System.out.println(">>>检查右上角失败 ("+m+","+n+")位置有棋子");
                return false;
            }
        }
        System.out.println("检查通过");
        System.out.println();
        return true;
    }
    
    /**
     * 打印当前已放置棋子的实际棋盘
     */
    public static void printActualBoard() {
        for (int row = 0; row < N; row++) {
            for (int column = 0; column < N; column++) {
                System.out.print(boards[row][column] + " ");
            }
            System.out.println();
        }
        System.out.println();
    }
    
    /**
     * 打印当前准备放入某棋子的虚拟棋盘
     */
    public static void printActualBoardMock(int rowMock, int columnMock) {
        for (int row = 0; row < N; row++) {
            for (int column = 0; column < N; column++) {
                if (row == rowMock && column == columnMock) {
                    System.out.print("* ");
                } else {
                    System.out.print(boards[row][column] + " ");
                }
            }
            System.out.println();
        }
    }
    
    /**
     * 打印棋盘的一些说明
     */
    public static void printBoardDesc() {
        System.out.println("为了方便说明,表格坐标将以这种格式打印");
        for (int row = 0; row < N; row++) {
            for (int column = 0; column < N; column++) {
                System.out.print("("+row+","+column+")" + " ");
            }
            System.out.println();
        }
    }

}

你可能感兴趣的:(算法,java)