• 《Java算法》Java回溯算法


    1. 概要

    回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。 

    2. 原理

    我们通过皇后问题来讲解回溯算法。

    回溯算法经典案例皇后问题:

    n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
    给定一个整数 n,返回所有不同的n皇后问题的解决方案。
    每一种解法包含一个明确的n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

    示例:   输入: 4 

    // 解法 1                                                                             // 解法 2
                   

    解释: 4 皇后问题存在两个不同的解法。

    回溯算法原理图解:

    如何判断皇后是否会被攻击: 横排,竖排好判断,对角线如何判断

    根据图解找到对角线规律。

    3 代码:

    import java.util.ArrayList;
    import java.util.List;
    
    public class Subject98 {
    
        //竖排被占登记,用于判断是否能够被竖排攻击
        int rows[]; //
        // "从左到右对角线" 登记,用于判断是否能够被竖排攻击
        int hills[];
        // "从右到左对角线" 登记,用于判断是否能够被竖排攻击
        int dales[];
        int n;
        // output
        List<List<String>> output = new ArrayList();
        // 皇后的位置
        int queens[];
    
        public static void main(String[] args) {
            List<List<String>> listList = new Subject98().solveNQueens(6);
            System.out.println(listList);
        }
    
        /**
         * 判断该位置是否会被攻击
         * @param row
         * @param col
         * @return
         */
        public boolean isNotUnderAttack(int row, int col) {
            int res = rows[col] + hills[row - col +  n - 1] + dales[row + col];
            return (res == 0) ? true : false;
        }
    
        /**
         * 将皇后放入该位置
         * @param row
         * @param col
         */
        public void placeQueen(int row, int col) {
            queens[row] = col;   //将皇后位置放入
            rows[col] = 1;   //竖排攻击位置
            hills[row - col +  n - 1] = 1;  // "从左到右对角线" 攻击位置
            dales[row + col] = 1;   //"从右到左对角线" 攻击位置
        }
    
        /**
         * 回溯皇后位置
         * @param row
         * @param col
         */
        public void removeQueen(int row, int col) {
            queens[row] = 0;
            rows[col] = 0;
            hills[row - col + n - 1] = 0;
            dales[row + col] = 0;
        }
    
        /**
         * 将满足条件的皇后位置放入output中
         */
        public void addSolution() {
            List<String> solution = new ArrayList<String>();
            for (int i = 0; i < n; ++i) {
                int col = queens[i];
                StringBuilder sb = new StringBuilder();
                for(int j = 0; j < col; ++j) sb.append(".");
                sb.append("Q");
                for(int j = 0; j < n - col - 1; ++j) sb.append(".");
                solution.add(sb.toString());
            }
            output.add(solution);
        }
    
        public void backtrack(int row) {
            for (int col = 0; col < n; col++) {
                if (isNotUnderAttack(row, col)) {
                    placeQueen(row, col);
                    // 皇后数量是否满足,满足则输出
                    if (row + 1 == n) addSolution();
                    // 不满足则继续
                    else backtrack(row + 1);
                    // 回溯。
                    removeQueen(row, col);
                }
            }
        }
    
        public List<List<String>> solveNQueens(int n) {
            this.n = n;
            rows = new int[n];
            hills = new int[2 * n - 1];
            dales = new int[2 * n - 1];
            queens = new int[n];
    
            backtrack(0);
            return output;
        }
    }

    来源:https://leetcode-cn.com/problemset/all/

    This moment will nap, you will have a dream; But this moment study,you will interpret a dream.
  • 相关阅读:
    rman备份,恢复
    异步事件回调机制原理探索 (转)
    stock
    将知识变成你的技能点
    Tomcat的URL中文乱码解决以及传输优化
    李洪强iOS开发之-入门指南
    WebSocket 和 Socket 的区别
    李洪强iOS开发之-修改状态栏的字体的颜色
    关于UDID和UUID的区别
    李洪强iOS开发之
  • 原文地址:https://www.cnblogs.com/jssj/p/12098636.html
Copyright © 2020-2023  润新知