51、52、N-皇后

  1. 示例:
  2. 官方的解
  3. N=4
  4. 代码

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

tu
上图为 8 皇后问题的一种解法。

给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。

每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

示例:

  • 输入: 4
  • 输出:
[
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]

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

官方的解

  • 深度优先,递归回溯
  • 数学规律
    • 行列记录 rows[row] = col
    • 正对角线记录 row - col + 2*n
    • 次对角线记录 row + col
    • 保证正对角线与次对角线不冲突

N=4

  • 正对角线记录
X 0 1 2 3
0 8 7 6 5
1 9 8 7 6
2 10 9 8 7
3 11 10 9 8
  • 次对角线记录
X 0 1 2 3
0 0 1 2 3
1 1 2 3 4
2 2 3 4 5
3 3 4 5 6

代码

class Solution {
    // 辅助变量
    int rows[];// 行列占领标记 0~n
    int hills[];// 正对角线占领标记 2n~4n-1
    int dales[];// 次对角线占领标记 0~2n-1
    int n;// 边长
    // output 结果集
    List<List<String>> output = new ArrayList<List<String>>();
    
    int queens[];// 记录皇后的位置
    
    // 判断当前位置是否会被其他皇后攻击
    public boolean isNotUnderAttact(int row,int col) {
        int res =  rows[col] + hills[row - col + 2*n] + dales[row + col];
        return (res == 0) ? true : false;
    }
    
    // 在(row,col)处放置皇后
    public void placeQueen(int row, int col) {
        queens[row] = col;// 第row行的第col列,放上皇后
        rows[col] = 1;// 第row行的第col列,占领行列
        hills[row - col + 2*n] = 1;// 占领正对角线
        dales[row + col] = 1;// 占领次对角线
    }
    // 移除(row,col)处放置的皇后
    public void removeQueen(int row,int col) {
        queens[row] = 0;// 移除皇后
        // 状态复原
        rows[col] = 0;// 第row行的第col列,释放行列
        hills[row - col + 2*n] = 0;// 释放正对角线
        dales[row + col] = 0;// 释放次对角线
    }
    
    // 构造某一个解
    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 backtract(int row){
        for (int col = 0;col < n;col++) {
            if (isNotUnderAttact(row,col)) {// 当前(row,col)位置没有皇后占领
                placeQueen(row,col);// 放置皇后
                if (row + 1 == n) {// 完成最后一行的皇后的寻找
                    addSolution();// 构造一个解。不需要return,需要回溯尝试其他情况
                } else {// 没有结束
                    // 深度优先递归
                    backtract(row+1);
                }
                // 回溯
                removeQueen(row,col); // 移除皇后
            }
        }
    }
    
    // 主方法
    public List<List<String>> solveNQueens(int n) {
        this.n = n;
        rows = new int[n];
        hills = new int[4*n - 1];
        dales = 
        new int[2*n - 1];
        queens =  new int[n];
        
        backtract(0);
        return output;
    }
}

52、求N皇后的解的个数

  • 直接修改51题的代码,将结果改为一个整数即可
class Solution {
    // 辅助变量
    int rows[];// 行列占领标记 0~n
    int hills[];// 正对角线占领标记 2n~4n-1
    int dales[];// 次对角线占领标记 0~2n-1
    int n;// 边长
    // output 结果
    int count = 0;
    
    int queens[];// 记录皇后的位置
    
    // 判断当前位置是否会被其他皇后攻击
    public boolean isNotUnderAttact(int row,int col) {
        int res =  rows[col] + hills[row - col + 2*n] + dales[row + col];
        return (res == 0) ? true : false;
    }
    
    // 在(row,col)处放置皇后
    public void placeQueen(int row, int col) {
        queens[row] = col;// 第row行的第col列,放上皇后
        rows[col] = 1;// 第row行的第col列,占领行列
        hills[row - col + 2*n] = 1;// 占领正对角线
        dales[row + col] = 1;// 占领次对角线
    }
    // 移除(row,col)处放置的皇后
    public void removeQueen(int row,int col) {
        queens[row] = 0;// 移除皇后
        // 状态复原
        rows[col] = 0;// 第row行的第col列,释放行列
        hills[row - col + 2*n] = 0;// 释放正对角线
        dales[row + col] = 0;// 释放次对角线
    }
    
    // 回溯算法
    public void backtract(int row){
        for (int col = 0;col < n;col++) {
            if (isNotUnderAttact(row,col)) {// 当前(row,col)位置没有皇后占领
                placeQueen(row,col);// 放置皇后
                if (row + 1 == n) {// 完成最后一行的皇后的寻找
                    // 不需要return,需要回溯尝试其他情况
                    count++;
                } else {// 没有结束
                    // 深度优先递归
                    backtract(row+1);
                }
                // 回溯
                removeQueen(row,col); // 移除皇后
            }
        }
    }
    
    public int totalNQueens(int n) {
        this.n = n;
        rows = new int[n];
        hills = new int[4*n - 1];
        dales = new int[2*n - 1];
        queens = new int[n];
        
        backtract(0);
        return count;
    }
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com

💰

Title:51、52、N-皇后

Count:1.2k

Author:攀登

Created At:2020-07-26, 00:19:44

Updated At:2024-06-15, 15:52:32

Url:http://jiafeimao-gjf.github.io/2020/07/26/51%E3%80%8152%E3%80%81N-%E7%9A%87%E5%90%8E/

Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.

×

Help us with donation