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;
}
};