题目描述
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
思路
- 根据题目的要求,每行、每列有且只有一个皇后,我们可以按照列的方式依次填入皇后,并保证新填入的皇后和已填入的所有皇后不会相互攻击;
- 选择stack数据结构存储合理的皇后位置,stack最底部的位置存储的是第一列的元素,越往上存储的元素对应越靠右的列;(应该也可以使用vector存储,在使用过程中发现stack不能遍历,需要反复拷贝)
- 根据stack已有的元素,挑选下一列中合理的pos(从上而下);如果能找到,则放进stack中,并重复步骤3;
- 当找到的元数有n个,则发现一种解法;然后弹出stack中一个元数,寻找该列(最后一列)中下一个合理的pos;
- 如果不能找到,则弹出stack中一个元素,并根据弹出元素的位置(至上而下)寻找该列中下一个合理的pos;
代码分析
首先定义二维数组中元数的结构,表示位置信息
struct position {
int _r;
int _l;
position() {
_r = 0;
_l = 0;
}
position(int r, int l) {
_r = r;
_l = l;
}
};
下面是我们的主函数
vector<vector<string>> solveNQueens(int n) {
_dimension = n;
vector<vector<string>> ret;
int row = n;
int line = n;
// each row has only one queen
// each line has only one queen
stack<position> s;
int next_row_start=0;
while(true) {
position next_pos = get_next_line_valid(s, next_row_start); // not conflict with all element now
if(!is_valid(next_pos)) { // can not find valid element
if(s.empty()) {
break;
}
next_row_start = s.top()._r+1; // move to next row in the same line
s.pop();
continue;
}
// valid element
s.push(next_pos);
next_row_start = 0; // reset
if(s.size() == n) { // find one solution
display(s, ret);
next_row_start = s.top()._r+1;
s.pop();
}
}
return ret;
}
- get_next_line_valid是根据已经选出的皇后位置(存放进stack中),挑选下一列中能出现皇后的位置。next_row_start变量的作用是保证每一列皇后的选取是至上而下进行,不会重复选取;
- is_valid是判断下一列能否返回一个合理的位置,如果不能,则弹出stack中的一个元数,并记录该元数的位置信息;
- 如果能找到一个合理的位置信息,则把它push进stack中;
- 如果所有列都选出合理的queue的位置,则调用display函数进行展示;
最后我们来看一下其他函数的实现
position get_next_line_valid(const stack<position>& s, int next_row_start) {
position ret{-1, -1}; // invalid
int line_idx = s.size();
for(int i=next_row_start; i!=_dimension; i++) { // top down direction
stack<position> tmp(s);
position cur{i, line_idx};
bool is_valid = true;
while(tmp.size()) {
if(is_conflict(tmp.top(), cur)) {
is_valid = false;
break;
}
tmp.pop();
}
if(is_valid) {
ret = cur;
break;
}
}
return ret;
}
bool is_valid(const position& pos) {
if(pos._r==-1 || pos._l==-1) return false;
return true;
}
bool is_conflict(const position& pos1, const position& pos2) {
if(pos1._r==pos2._r || pos1._l==pos2._l) {
return true;
}
int row_diff = (pos1._r-pos2._r > 0) ? pos1._r-pos2._r : pos2._r-pos1._r;
int line_diff = (pos1._l-pos2._l > 0) ? pos1._l-pos2._l : pos2._l-pos1._l;
if(row_diff == line_diff) {
return true;
}
return false;
}
void display(stack<position> s, vector<vector<string>>& ret) {
assert(s.size() == _dimension);
vector<string> cur;
cur.resize(_dimension);
while(s.size()) { // from right to left direction
const position& p = s.top();
for(int i=0; i!=_dimension; i++) { // for each string
if(p._r == i) { // this is the queen
cur.at(i) = string(1, 'Q') + cur.at(i);
}else {
cur.at(i) = string(1, '.') + cur.at(i);
}
}
s.pop();
}
ret.push_back(move(cur));
}