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


    一、背景

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

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

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

    二、解法

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

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

    三、代码

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

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

    话不多说,上码

    1. public class NQueen {
    2. // N个皇后,4打印过程较短直观,改成8就是八皇后
    3. public static int N = 4;
    4. // 初始化一个正方形方格
    5. public static int[][] boards = new int[N][N];
    6. // 方案个数
    7. public static int result = 0;
    8. public static void main(String[] args) {
    9. printBoardDesc();
    10. printActualBoard();
    11. System.out.println("游戏开始...\n");
    12. putQueen(0);
    13. System.out.println("游戏结束,找到方案个数=" + result);
    14. }
    15. /**
    16. * 在某一列放置皇后
    17. */
    18. public static void putQueen(int row) {
    19. if (row == N) {
    20. // 能走到这里说明棋盘每一行都放了一个棋子并且通过了校验,这就是一个可用答案
    21. System.out.println("---找到一种方案---");
    22. printActualBoard();
    23. result++;
    24. } else {
    25. System.out.println("开始在第"+row+"行放棋子");
    26. // row指定了新的一行,在这一行从头逐列向右扫描,这时每行只填一次,所以check方法内部不用判断同一行是否有其他棋子
    27. int totalColumn = N;
    28. for (int column = 0; column < totalColumn; column++) {
    29. if (check(row, column)) {
    30. boards[row][column] = 1;
    31. putQueen(row + 1); // 最好的情况是一直递归往下找
    32. System.out.println("\n【回溯】此时棋盘内容是");
    33. printActualBoardMock(row, column);
    34. System.out.println();
    35. boards[row][column] = 0; // 找不到需要回溯
    36. }
    37. }
    38. }
    39. }
    40. /**
    41. * 检测当前位置是否可用
    42. */
    43. public static boolean check(int row, int column) {
    44. System.out.println("\n开始检查,当前准备放的位置是("+row+","+column+") 棋盘内容是:");
    45. printActualBoardMock(row, column);
    46. // 同一列从顶向下检查是否有皇后
    47. for (int i = 0; i < row; i++) {
    48. if (boards[i][column] == 1) {
    49. System.out.println(">>>检查列失败 ("+i+","+column+")位置有棋子");
    50. return false;
    51. }
    52. }
    53. // 向左上角逐个检查是否有皇后
    54. for (int m = row - 1, n = column - 1; m >= 0 && n >= 0; m--, n--) {
    55. if (boards[m][n] == 1) {
    56. System.out.println(">>>检查左上角失败 ("+m+","+n+")位置有棋子");
    57. return false;
    58. }
    59. }
    60. // 向右上角逐个检查是否有皇后
    61. for (int m = row - 1, n = column + 1; m >= 0 && n < N; m--, n++) {
    62. if (boards[m][n] == 1) {
    63. System.out.println(">>>检查右上角失败 ("+m+","+n+")位置有棋子");
    64. return false;
    65. }
    66. }
    67. System.out.println("检查通过");
    68. System.out.println();
    69. return true;
    70. }
    71. /**
    72. * 打印当前已放置棋子的实际棋盘
    73. */
    74. public static void printActualBoard() {
    75. for (int row = 0; row < N; row++) {
    76. for (int column = 0; column < N; column++) {
    77. System.out.print(boards[row][column] + " ");
    78. }
    79. System.out.println();
    80. }
    81. System.out.println();
    82. }
    83. /**
    84. * 打印当前准备放入某棋子的虚拟棋盘
    85. */
    86. public static void printActualBoardMock(int rowMock, int columnMock) {
    87. for (int row = 0; row < N; row++) {
    88. for (int column = 0; column < N; column++) {
    89. if (row == rowMock && column == columnMock) {
    90. System.out.print("* ");
    91. } else {
    92. System.out.print(boards[row][column] + " ");
    93. }
    94. }
    95. System.out.println();
    96. }
    97. }
    98. /**
    99. * 打印棋盘的一些说明
    100. */
    101. public static void printBoardDesc() {
    102. System.out.println("为了方便说明,表格坐标将以这种格式打印");
    103. for (int row = 0; row < N; row++) {
    104. for (int column = 0; column < N; column++) {
    105. System.out.print("("+row+","+column+")" + " ");
    106. }
    107. System.out.println();
    108. }
    109. }
    110. }

  • 相关阅读:
    华大单片机KEIL报错_WEAK的解决方案
    Python小总结
    1.并发编程的本质问题
    [数据集][目标检测]睡岗检测数据集VOC+YOLO格式3290张4类别
    Amazon EKS绑定alb 使用aws-load-balancer-controller(Ingress Controller)对外提供服务
    如何更快地学会任何事情?
    【重识云原生】第六章容器6.3.3节——Kube-Scheduler使用篇
    盒子(Box, ACM/ICPC NEERC 2004, UVa1587)rust解法
    C Primer Plus(6) 中文版 第9章 函数 9.7 指针简介 9.8 关键概念
    CentOS下对安装不同ModSecurity版本的Nginx的并发性能测试
  • 原文地址:https://blog.csdn.net/u011704894/article/details/132843877