n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例:
输入:4
输出:[
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],
["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
解释: 4 皇后问题存在两个不同的解法。
分析:若在棋盘上已放置一个皇后,以这个皇后为中心,上、下、左、右、左上、左下、右上、右下8个方向的位置全被占据。
回溯算法:N皇后问题,对于N*N棋盘,每行都要放置1个且只能放置1个皇后。利用递归对棋盘的每一行放置皇后,放置时,按列顺序寻找可以放置皇后的列,若可以放置皇后,将皇后放置到位置,并更新mark标记数组,递归进行下一行的皇后放置;当该次递归结束后,恢复mark标记数组,并尝试下一个可能放皇后的列。
当递归可以完成N行的N个皇后放置,则将该结果保存并返回。
class Solution{
vector<vector<string>> solveNQueens(int n) {
vector<vector<int>> mark;
vector<vector<string>> result;
vector<string> temp; //存放某次结果,当完成一次递归成功找到结果后将temp放入result中
//初始化标记数组和临时结果
for(int i = 0; i < n; i++) {
mark.push_back(vector<int>());
for(int j = 0; j < n; j++) {
mark[i].push_back(0);
}
temp.push_back("");
temp[i].append(n,'.');
}
generate(0,n,temp,result,mark);
return result;
}
void push_queen(int x,int y,vector<vector<int> > &mark) {
//两个方向数组
static const int dx[] = {-1,1,0,0,-1,-1,1,1};
static const int dy[] = {0,0,-1,1,-1,1,-1,1};
mark[x][y] = 1;
//以x,y为中心,按照八个方向向外延申N个距离,只要不超过边界,就将这个位置标记为已经被占据
for(int i = 1; i < mark.size(); i++) {
for(int j = 0; j < 8; j++) {
int new_x = x + dx[j] * i;
int new_y = y + dy[j] * i;
if(new_x >=0 && new_x < mark.size() && new_y >= 0 && new_y < mark.size()) {
mark[new_x][new_y] = 1;
}
}
}
}
void generate(int k,int n,vector<string> &temp,vector<vector<string> > &result,vector<vector<int> > &mark) {
if(k == n) { //这次递归完成了N皇后的放置
result.push_back(temp);
return;
}
for(int i = 0; i < n; i++) { //按顺序每列尝试放置皇后
if(mark[k][i] == 0) { //这一列可以放置皇后
vector<vector<int>> tmp_mark = mark; //临时的标记数组
temp[k][i] = 'Q'; //记录当前皇后的位置
push_queen(k,i,mark); //更新能放皇后的位置
generate(k+1,n,temp,result,mark); //递归下一行
mark = tmp_mark; //下一行不能放,回溯到当前行,继续往下一列放置
temp[k][i] = '.'; //当前尝试放皇后的位置重新置为'.'
}
}
}
};
int main(void) {
vector<vector<string> > result;
Solution s;
result = s.solveNQueens(4);
for(int i = 0; i < result.size(); i++) {
for(int j = 0; j < result[i].size(); j++) {
cout<<result[i][j]<<endl;
}
cout<<endl;
}
return 0;
}