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

皇后是一个强大的NPC,所谓一山不容二虎,一向不容二后,所以摆放的限制规则是这个皇后的横向、纵向、斜向都不能有其他皇后。
这个问题其实是非常难的,数学王子高斯认为有76种解法,只是现在有了计算机,渣渣如我也能算出更多的摆法,八皇后应该是有92种解法。

这个问题可以使用回溯法来解题,回溯法简单来说就是:
把问题的解空间转变为图或者树的数据结构,然后使用深度优先搜索(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();
- }
- }
-
- }