题目链接:
https://leetcode-cn.com/problems/n-queens/
难度:困难
51. N 皇后
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
提示:
皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。
nクイーンの質問、私はまだ若い頃にバックトラックを作成しました。これは非常に一般的な考えですが、作成時に問題が発生しました!彼らが同じ対角線上にあるかどうか見分ける方法がわかりません。。。
まず、バックトラッキングメソッドがset unordered_set <int>を使用して同じ列にないこと、および同じスラッシュ(stlがまだ使用されていないこと...)
が同じ列の
対角線上にないこと、同じフォワードスラッシュ
上にないこと、バックダイアゴナル、同じバックスラッシュ上にないことを保証することを明確にします。
(私はキューを使用して最初にバックトラックの結果を達成したいと考えていました。結果はますますカオスになり、それから問題の解決策を検討しました。
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
// ans 返回
vector<vector<string>> ans;
// queens 记录本次的答案
vector<int> queens(n,-1);
unordered_set<int> columns;
unordered_set<int> diagonal;
unordered_set<int> backdiagonal;
solve(ans,queens,n,0,columns,diagonal,backdiagonal);
return ans;
}
void solve(vector<vector<string>>& ans,vector<int>& queens,int n,int row,unordered_set<int>& columns,unordered_set<int>& diagonal, unordered_set<int> &backdiagonal){
if(row==n){
// 结束 答案正确
vector<string> s=getans(queens, n);
ans.push_back(s);
}else{
// 第row行的n种情况(列)
for(int i=0;i<n;++i){
// 行 斜线
if(columns.find(i)!=columns.end()){
continue;
}
int diag=row-i;
if(diagonal.find(diag)!=diagonal.end()){
continue;
}
int backdiag=row+i;
if(backdiagonal.find(backdiag)!=backdiagonal.end()){
continue;
}
// queens 集合
queens[row]=i;
columns.insert(i);
diagonal.insert(diag);
backdiagonal.insert(backdiag);
solve(ans,queens,n,row+1,columns,diagonal,backdiagonal);
// 去除 保证下次递归正确
queens[row]=-1;
columns.erase(i);
diagonal.erase(diag);
backdiagonal.erase(backdiag);
}
}
}
// queens记录位置 转化为vector<string>
vector<string> getans(vector<int> &queens,int n){
vector<string> ans;
for(auto a:queens){
string s=string(n, '.');
s[a]='Q';
ans.push_back(s);
}
return ans;
}
};
問題の
非常に明確な解決策を記述した2進数の記録された座標を使用するためのより良いクエリ方法(nb兄貴は私が初心者とは思えなかった)
があります(私は忘れます...)が、最大長はintに設定されています今64
将数值(int) 写为 2 进制的 每一位代表该行的一个位置(0代变可以 1代表不可)
columns 保证不在同一列上
diagonal 保证不在同一正斜线上
backdiagonal 保证不在同一反斜线上
对于 diagonal backdiagonal ,下一行的不能放皇后的位置是上一行的 diagonal 左移 和 backdiagonal 的右移
x & (−x) 可以获得 x 的二进制表示中的最低位的 1 的位置
x & (x−1) 可以将 x 的二进制表示中的最低位的 1 置成 0
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> ans;
vector<int> queens(n,-1);
solve(ans,queens,n,0,0,0,0);
return ans;
}
void solve(vector<vector<string>>& ans,vector<int>& queens,int n,int row,int columns,int diagonal, int backdiagonal){
if(row==n){
vector<string> s=getans(queens, n);
ans.push_back(s);
}else{
int pos=((1<<n)-1)&(~(columns|diagonal|backdiagonal));
while(pos!=0){
int postion=pos&(-pos);
pos=pos&(pos-1);
int column=__builtin_ctz(postion);
queens[row]=column;
solve(ans,queens,n,row+1,columns|postion,(diagonal|postion)>>1,(backdiagonal|postion)<<1);
queens[row] = -1;
}
}
}
vector<string> getans(vector<int> &queens,int n){
vector<string> ans;
for(auto a:queens){
string s=string(n, '.');
s[a]='Q';
ans.push_back(s);
}
return ans;
}
};