描述
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
提示:
皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。
思路
- 题述里最后输出的是一个一维数组,其中每个数组元素是一个vector,代表了一张棋盘。
vector<vector<string> > res;
也就是说每张棋盘的形式是vector,所以先定义一个内容为vector类型的vector,用来装多张棋盘,作为最终的解集。初始将每张棋盘设置为共n组,每组n个“.”的初始值,也就是每张棋盘初始为空。vector<string> chess(n, string(n, '.'));
- 从第0行开始考虑放置皇后,首先从第0列开始放,也就是当前坐标是chess[0][0],判断当前位置的上方,左上对角线、右上对角线有无皇后,没有则当前位置可以放置皇后,这行已经不能在放下一个皇后了,再考虑下一行的第0列…如果放置皇后之后在上方及对角线上有皇后冲突了,则不在此位置放,考虑本行的下一个位置。如此循环,当行已经超过了棋盘行数n后就不能再放了,此时一定能得到一张八皇后的棋盘,将其添加到解集中即可。
- 回溯的通用模版:
void backTrack(){
for(遍历){
chess[row][column] = 'Q';//放置皇后
backTrack();//递归
chess[row][column];//函数能执行到这说明此位置放皇后的话无解
}
}
解答
class Solution {
public:
//定义保存最终结果的一维数组,大小为1*m,每一个数组元素是一个vector,代表一张棋盘
vector<vector<string> > res;
int N = 0;
vector<vector<string>> solveNQueens(int n) {
N = n;
//初始化为n个“......”的vector
//形式:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
vector<string> chess(n, string(n, '.'));
//从第0行开始放置皇后
backTrack(chess, 0);
return res;
}
void backTrack(vector<string>& chess, int row){
if(row == N){//已经到了最后一行
res.push_back(chess);
return;
}
//从第0列开始尝试放皇后
for(int column = 0;column < N;++ column){
if(isValue(chess, row, column)){
chess[row][column] = 'Q';
backTrack(chess, row + 1);
chess[row][column] = '.';
}
}
}
//判断chess[row][column]的上方、左上方对角线、右上方对角线有无皇后
bool isValue(vector<string>& chess, int row, int column){
//判断当前坐标的上方有无皇后
for(int i = 0;i < N; ++ i)
if(chess[i][column] == 'Q') return false;
//判断当前坐标的左上对角线有无皇后
for(int i = row-1,j = column-1;i >= 0 && j <= N; --i, --j)
if(chess[i][j] == 'Q') return false;
//判断当前坐标的右上对角线有无皇后
for(int i = row-1, j = column+1;i >= 0 && j <= N; --i, ++j)
if(chess[i][j] == 'Q') return false;
return true;
}
};
最终8皇后问题执行了15720次,共有92个解: