【问题】n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例:

输入: 4
输出:
[[".Q..", // 解法 1
"…Q",
"Q…",
"..Q."],
["..Q.", // 解法 2
"Q…",
"…Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。

【思路】N皇后在不同地方,不同场合都有听到过这个问题,但仔细分析了一下,发现和原来的数独问题十分的类似,也是约束编程+回溯法的思想!我们首先分析一下两者的相同点和不同点:

解数独问题:

N确定,为9x9的网格,约束条件为:向未知位置填入1-9的数字,使得该数所在的行和列均不重复以及所在的3x3网格内也不重复,因此我们需要使用col_[9][9]、row_[9][9]、block_[9][9]来储存数字在行、列和网格中是否被使用过。使用过标记为true,否则标记为false。

N皇后问题:

N不确定,因此我们需要在函数中建立辅助空间,而不能建立成成员变量,约束条件为:在NxN的网格中任意摆放皇后Q,为了避免皇后之间不能相互攻击,该位置所在的行、列以及主、副对角线均只能有这一个Q,因此我们需要使用cols_标记每一列是否存在Q,使用diag1s_、diag2s_来标记主、副对角线是否存在Q。

当了解到这些之后,整个回溯递归方法就十分清晰了,中间有一个地方十分让人困惑,ll和rr是如何求解的呢?这就要说到主、副对角线的性质了!!!

  • 主对角线:col+row的值是一定的,范围[0, 2n-2],从零开始

  • 副对角线:col-row的值是一定的,为了使索引有效,加上定值n-1, 最终范围[0, 2n-2]

有人会问,row怎么遍历,emmm, 递归修改的参数就是row,其实也就相当于遍历了整个网格,但速度还可以,中间存在了很多条件判断进行剪枝!

class Solution {
public:
    void solve(vector<vector<string>>& res, vector<string>& tmp, vector<bool>& cols_, vector<bool>& diag1s_, vector<bool>& diag2s_, int n, int row){
        if(row == n){
            res.push_back(tmp);
            return;
        }
        for(auto col = 0; col < n; col++){
            int ll = row + col;
            int rr = row - col + n - 1;
            if (cols_[col] && diag1s_[ll] && diag2s_[rr]){
                tmp[row][col] = 'Q';
                cols_[col] = false;
                diag1s_[ll] = false;
                diag2s_[rr] = false;

                solve(res, tmp, cols_, diag1s_, diag2s_, n, row+1);

                tmp[row][col] = '.';
                cols_[col] = true;
                diag1s_[ll] = true;
                diag2s_[rr] = true;
            }
        }
    }

    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>> res;
        vector<string> tmp(n, string(n, '.'));
        vector<bool> cols_(n, true);
        vector<bool> diag1s_(2*n-1, true);
        vector<bool> diag2s_(2*n-1, true);
        solve(res, tmp, cols_, diag1s_, diag2s_, n, 0);
        return res;
    }

};