N皇后问题-I
问题描述
n皇后问题是将n个皇后放置在n*n的棋盘上,皇后彼此之间不能相互攻击。
给定一个整数n,返回所有不同的n皇后问题的解决方案。
每个解决方案包含一个明确的n皇后放置布局,其中“Q”和“.”分别表示一个女王和一个空位置。
样例:
对于4皇后问题存在两种解决的方案:
[
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."],
["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]
]
算法思路
基本的思路就是全排列的DFS问题,也可以说是回溯问题。大家可以不区分这两个概念,认为回溯和DFS是一样的问题。
这道题让求出所有的方案,基本上求所有方案的问题,没有什么别的做法,就是枚举,暴力搜索。那么枚举的话,90%都是用DFS来做。那你可能要问了,怎么转换成DFS问题那。
其实是有一个模板的(针对全排列的DFS的模板):
vector<vector<int>> permute(vector<int> &nums) {
vector<vector<int>> results;
// 不用排序
dfs(nums, vector<bool>(nums.size(), false), vector<int>(), results);
return results;
}
// 1. 定义:找到所有permutation开头的排列,加到results中。比如所有以1开头的排列,或所有以空开头的排列
void dfs(vector<int> nums, vector<bool> visited, vector<int> permutation, vector<vector<int>> & results) {
// 2. 递归的出口
if (permutation.size() == nums.size()) {
results.push_back(permutation);
return;
}
// 3. 递归的拆解
for (int i = 0; i < nums.size(); ++i) {
if (visited[i]) {
continue;
}
permutation.push_back(nums[i]);
visited[i] = true;
dfs(nums, visited, permutation, results);
visited[i] = false;
permutation.pop_back();
}
}
对于这个模板,还请个位理解记忆并背诵。然后再这个基础上我们尝试DFS来搜索所有的可能放置方案,对于有效的方案记录下来,无效的方案直接跳过,完整AC代码:
class Solution {
public:
/*
* @param n: The number of queens
* @return: All distinct solutions
*/
vector<vector<string>> solveNQueens(int n) {
vector<vector<int>> results;
dfs(n, vector<int>(), results);
vector<vector<string>> ret(results.size(), vector<string>(n,string(n,'.')));
// 构造ret, results中放置的是第i行皇后,应该放置的位置[0,n-1]
for (int i = 0; i < results.size(); ++i) {
vector<int> queuens = results[i];
for (int j = 0; j < queuens.size(); ++j) {
ret[i][j][queuens[j]] = 'Q';
}
}
return ret;
}
void dfs(int n, vector<int> permutation, vector<vector<int>> &results) {
if (permutation.size() == n) {
results.push_back(permutation);
return;
}
for (int i = 0; i < n; ++i) {
if (!isValid(permutation, i)) {
continue;
}
permutation.push_back(i);
dfs(n, permutation, results);
permutation.pop_back();
}
}
bool isValid(vector<int> cols, int chosenCol) {
int rows = cols.size();
for (int i = 0; i < cols.size(); ++i) {
int col = cols[i];
// 同一列
if (chosenCol == col) {
return false;
}
// 同一斜线
if (i - rows == col - chosenCol) { // 左斜向下
return false;
}
if (i - rows == chosenCol - col) { // 右斜向上
return false;
}
}
return true;
}
};