N皇后

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

思路
使用回溯算法,试探路径,核心在于for循环里面做递归,在递归调用之前做选择,在递归之后撤销选择,具体回溯框架如下

def backtrack(路径,选择列表)
    if 满足结束条件:
        result.add(路径)
        return 
    for 选择 in 选择列表:
        做选择
        backtrack(路径,选择列表)
        撤销选择

在N皇后问题中,我们看似要在n×n个位置中做选择,实质上根据行冲突和列冲突,只用在每一行或每一列中做选择,
所以只要一重循环,做出选择该层循环的选择后,进入下一个状态,例如在第一行遍历列位置,做出选择后,进入第二行
回溯具体过程为

class Solution {
public:
    vector<vector<string>> res;//存储最终结果
    vector<vector<string>> solveNQueens(int n) {
        vector<string> board(n,string(n,'.'));//初始化棋盘,全为空
        backtrack(board,0);
        return res;
    }
//路径:board中小于row的那些行都已经放置
//选择列表:第row行所有列都可以作为选择
//结束条件:row超过board最后一行
    void backtrack(vector<string>& board,int row){
        //触发结束条件
        if(row == board.size()){
            res.push_back(board);//结束后将该棋盘布局添加至结果
            return;
        }

        int n = board[row].size();//避免重复计算
        for(int col = 0; col < n; col++){
            //排除不合法选择
            if(!isValid(board,row,col))
                continue;
            //做选择
            board[row][col]='Q';
            //进入下一行决策
            backtrack(board,row+1);
            //撤销选择
            board[row][col]='.';//撤销选择是为了进入该行的下一个选择
        }
    }
    bool isValid(vector<string>& board,int row,int col){
        int n = board[row].size();
        //检查列是否冲突
        for(int i=0;i<n;i++){
            if(board[i][col] =='Q') return false;
        }
        //检查右上方冲突
        for(int i=row-1,j=col+1;i>=0&&j<n;i--,j++){
            if(board[i][j] =='Q') return false;
        }
        //检查左上方冲突
        for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){
            if(board[i][j] =='Q') return false;
        }
        return true;        
    }
};
posted @ 2022-05-10 10:41  失控D大白兔  阅读(48)  评论(0编辑  收藏  举报