N-Queens
原题链接N-Queens
n皇后问题,和数独问题一样,都是回溯法的经典题目。
n皇后问题约束是任意两个皇后不能在一行,不能在一列,不能在同一个45度直线,不能在同一个135度直线上。所以求解时需要记录
- 当前行是否已经存在一个皇后
- 当前列是否已经存在一个皇后
- 当前位置所在的45度直线上是否已经存在一个皇后
- 当前位置所在的135度直线上是否已经存在一个皇后
因为n行n个皇后,所以每一行有且仅有一个皇后,那么可以不需要记录当前行是否已经存在皇后,只要在当前行找到一个位置容纳皇后,就开始在下一行寻找,即每一行遍历右边列,找到满足后三个条件的位置即可。
所有的约束条件都可以用数组记录,即
- flag_col[column]表示column列是否已经存在一个皇后
- flag_45[p]表示位置[row, column]所在的45度直线是否出现过皇后,其中p是row和column的函数
- flag_135[q]表示位置[row, column]所在的135度直线是否出现过皇后,其中q是row和column的函数
比较不要记录的就是45度和135度直线上的情况,可以利用数学思维简化。
- 对于45度直线,可知斜率为1,即解析式可以写成
y = x + b
。那么对于在同一条45度直线的点,截距b是一定的,所以可以用y - x来代表某一条45度直线,所以可以另m = column - row
。但是column可能会小于row,导致m为负值,所以可以将m增加n - 1让m变为正值,即m = n - 1 + column - row
- 对于135度直线,可知斜率为-1,同理可知另
m = column + row
,此时不存在m为负值的情况,无须加n - 1 - 不过需要注意的是flag_45和flag_135数组的大小是2 * n - 2,设置成2 * n即可
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> res;
vector<string> cur(n, string(n, '.'));
vector<int> flag_col(n, 1), flag_45(2 * n, 1), flag_135(2 * n, 1);
solveNQueens(n, 0, cur, res, flag_col, flag_45, flag_135);
return res;
}
private:
void solveNQueens(int n, int row, vector<string>& cur, vector<vector<string>>& res, vector<int>& flag_col, vector<int>& flag_45, vector<int>& flag_135)
{
if(row >= n)
{
res.emplace_back(cur);
return;
}
/* 回溯法 */
for(int i = 0; i < n; ++i)
{
if(flag_col[i] && flag_45[n - 1 + i - row] && flag_135[i + row])
{
cur[row][i] = 'Q';
flag_col[i] = flag_45[n - 1 + i - row] = flag_135[i + row] = 0;
solveNQueens(n, row + 1, cur, res, flag_col, flag_45, flag_135);
cur[row][i] = '.';
flag_col[i] = flag_45[n - 1 + i - row] = flag_135[i + row] = 1;
}
}
}
};