• 回溯算法


    (1)问题描述

      在 n × n 格的棋盘上放置彼此不受攻击的 n 个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n 后问题等价于在 n × n 的棋盘上放置 n 个皇后,任何 2 个皇后不放在同一行或同一列或同一斜线上。

      

    (2)算法描述

      a. 将第一个皇后放置在第一行的第一个空格里;

      b. 对于第二行,从第一个空格开始寻找不与第一行的皇后冲突的空格。找到的第一个不冲突的空格是第2个;

      c. 对于第三行,这时已经找不到与之前放置的两个皇后不冲突的空格了。把当前行恢复初始状态,返回到上一行;

      d. 在当前行皇后所占的空格之后寻找一个不与之前皇后冲突的位置。有两种情况,如果找到了则把当前行的皇后移动到该位置,然后处理下一行。如果直到最后当前行的最后一个空格也没有找合适的位置,则把当前行恢复初始状态,继续回溯到上一行;

      e. 把最后一个皇后成功安置在最后一行,代表找到了一种可行解。返回步骤 d ;

      f. 当需要回溯到第 0 行的时候代表已经找遍了所有可能的可行解。

    (3)算法代码

    public class NQueen {
    
        /**
         * 皇后数量
         */
        private static Integer num;
    
        /**
         * 可行解的总数
         */
        private static Integer sum = 0;
    
        /**
         * n 皇后当前解
         */
        private static Integer[] answer;
    
        /**
         * 初始化数据
         */
        private static void initData() {
            Scanner input = new Scanner(System.in);
            System.out.println("请输入 n 皇后数量:");
            num = input.nextInt();
    
            answer = new Integer[num];
        }
    
        /**
         * 判断当前皇后存放是否可行
         */
        private static Boolean bound(int t) {
            for (int i = 0; i < t; i++) {   // 判断第 t 个皇后和前面已经存放好的第 (0 ~ num -1) 个皇后之间是否存在同列同斜率
                /**
                 * 1)Math.abs(t - i) 表示两点的纵坐标;
                 * 2)Math.abs(answer[t] - answer[i]) 表示两点的横坐标;
                 * 3)answer[t] == answer[i] 表示两个皇后是否同列;
                 */
                if ((Math.abs(t - i) == Math.abs(answer[t] - answer[i])) || (answer[t] == answer[i])) {
                    return false;
                }
            }
            return true;
        }
    
        /**
         * 回溯求解 n 皇后问题
         */
        private static void backtrack(int t) {
            if (t == num) {                                 // 第 n 个皇后已经填完毕,满足条件
                // 输出当前可行解
                Stream.of(answer).forEach(element -> System.out.print(element + " "));
                System.out.println();
                sum++;
                return;
            }
            for (int j = 0; j < num; j++) {     // 将第 t 个皇后依次放入 (0 ~ num - 1) 个位置进行判定
                answer[t] = j;                  // 将第 t 个皇后放入 j 位置
                if (bound(t)) {                 // 判断将第 t 个皇后放入 j 位置,是否符合条件
                    backtrack(t + 1);
                }
            }
        }
    
        public static void main(String[] args) {
            // 初始化数据
            initData();
    
            // 回溯求解 n 皇后问题
            backtrack(0);
            
            System.out.println("可行性解总数: sum = " + sum);
        }
    
    }
    n皇后算法核心代码

    (4)输入输出

    请输入 n 皇后数量:
    5
    0 2 4 1 3 
    0 3 1 4 2 
    1 3 0 2 4 
    1 4 2 0 3 
    2 0 3 1 4 
    2 4 1 3 0 
    3 0 2 4 1 
    3 1 4 2 0 
    4 1 3 0 2 
    4 2 0 3 1 
    可行性解总数: sum = 10
    View Code

    (5)总结

      n 皇后问题同样提现了回溯算法的核心思想,依次深度搜索,回溯到上一层;但是不与 子集树、排序树相同,有一定的区别,每一个皇后寻找位置都是从头依次找合适的位置,直到行尾才结束,然后回溯到上一层;时间复杂度为:O(nn);

      同样希望大家能动手实践一下,画一画走一下代码流程,加深回溯算法的思想。

  • 相关阅读:
    DIV 设置垂直居中
    JavaScript--什么是函数
    JavaScript--引用JS外部文件
    JavaScript--如何插入JS
    CSS-类和ID选择器的区别
    CSS-ID选择器
    CSS类选择器
    CSS样式介绍
    HTML--使用mailto在网页中链接Email地址
    HTML--form表单中的label标签
  • 原文地址:https://www.cnblogs.com/blogtech/p/12303688.html
Copyright © 2020-2023  润新知