3

Leetcode 通过率最高的困难题 N皇后 II 【回溯解法-剪枝】

 2 years ago
source link: https://segmentfault.com/a/1190000041103524
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

简约图文你好2022祝福问候公众号推送首图@凡科快图.png

*n 皇后问题 研究的是如何将 n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。*

皇后走法规则

皇后的走法是:可以横直斜走,格数不限。因此要求皇后彼此之间不能相互攻击,等价于要求任何两个皇后都不能在同一行、同一列以及同一条斜线上。

输入:n = 4
输出:2

解释:如上图所示,4 皇后问题存在两个不同的解法。

输入:n = 1
输出:1

提示:
1 <= n <= 9

  1. 定义判断当前位置的检验函数,约束条件包含 ,不能同行,不能同列,不能同对角线(45度和135度)
  2. 定义棋盘;标准回溯处理;

使用回溯的具体做法是:依次在每一行放置一个皇后,每次新放置的皇后都不能和已经放置的皇后之间有攻击,即新放置的皇后不能和任何一个已经放置的皇后在同一列以及同一条斜线上。当 NNN 个皇后都放置完毕,则找到一个可能的解,将可能的解的数量加 111。

图片来源

var totalNQueens = function (n) {
    let count = 0; //皇后可放置的总数
    let isValid = (row, col, board, n) => {
        //所在行不用判断,每次都会下移一行
        //判断同一列的数据是否包含
        for (let i = 0; i < row; i++) {
            if (board[i][col] === 'Q') {
                return false
            }
        }
        //判断45度对角线是否包含
        for (let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
            if (board[i][j] === 'Q') {
                return false
            }
        }
        //判断135度对角线是否包含
        for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; j--, i--) {
            if (board[i][j] === 'Q') {
                return false
            }
        }
        return true
    }

    let backTracing = (row, board) => {
        //走到最后一行,统计次数
        if (row === n) {
            count++;
            return
        }

        for (let x = 0; x < n; x++) {
            //判断该位置是否可以放置 皇后
            if (isValid(row, x, board, n)) {
                board[row][x] = 'Q'; //放置皇后
                backTracing(row + 1, board); //递归
                board[row][x] = '.'; //回溯,撤销处理结果
            }
        }
    }
    backTracing(0, board)
    let board = [...Array(n)].map(v => v = ([...Array(n)]).fill('.')) //棋盘
    return count
};

主要运用了回溯算法;而解决一个回溯问题,实际上就是一个决策树的遍历过程。

let backtracking=(路径,选择列表) =>{
    if (满足结束条件)) {
        存放路径;
        return;
    }
    for (选择:路径,选择列表) {
        做出选择;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}
  1. 1.路径:也就是已经做出的选择。
  2. 2.选择列表:也就是你当前可以做的选择。
  3. 3.结束条件:也就是到达决策树底层,无法再做选择的条件。
  1. 1.用约束条件剪除得不到的可行解的子树
  2. 2.用目标函数剪取得不到的最优解的子树

回溯法的一般步骤:

  1. 1.设置初始化的方案(给变量赋初始值,读入已知数据等)
  2. 2.变换方式去试探,若全部试完侧转(7)
  3. 3.判断此法是否成功(通过约束函数),不成功则转(2)
  4. 4.试探成功则前进一步再试探
  5. 5.正确方案还是未找到则转(2)
  6. 6.以找到一种方案则记录并打印
  7. 7.退回一步(回溯),若未退到头则转(2)
  8. 8.已退到头则结束或打印无解

每天精进,继续加油!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK