LeetCode—笔记—51、N皇后——递归回溯,个人思路,简单易懂
51. N 皇后
n 皇后问题 研究的是如何将 n
个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
一、题目分析
根据题目意思是就是N*N的矩形棋盘上,放置N枚棋子,每行一个,每列一个,每斜线一个;
二、解题思路
我们可以这样想,以4*4为例:
1、在每行依次放置棋子,但每次只能放置一枚,如第一行:分别在0,1,2,3列放置一枚棋子,第二行再从0,1,2,3列放置一枚棋子,以此类推;
2、放置每一枚棋子后总棋子数目减一;
3、放置棋子时判断是否满足题目要求,如果满足进行下一行放置,不满足遍历下一次位置。
4、采用递归的方法放置每一行
5、怎么判断放置的棋子是否在之前的棋子的列上与斜线上?第三节解释
三、代码撰写思路及其细节
怎么判断放置的棋子是否在之前的棋子的列上与斜线上?
因为采用每行放置的方式所以不用考虑行重复,每次放置时纪录本行放置的列的位置,数组为addr_row_col_[n];然后判断是否在同一列,就很简单,遍历数组判断col==addr_row_col_[i];即可。那么怎么判断斜线呢,也很简单,就是
c
o
l
=
=
a
d
d
r
_
r
o
w
_
c
o
l
_
[
i
]
−
(
r
o
w
−
i
)
;
c
o
l
=
=
a
d
d
r
_
r
o
w
_
c
o
l
_
[
i
]
+
(
r
o
w
−
i
)
;
col==addr\_row\_col\_[i]-(row-i);\\ col==addr\_row\_col\_[i]+(row-i);\\
col==addr_row_col_[i]−(row−i);col==addr_row_col_[i]+(row−i);
不明白可以动手画一画。
然后代码里的注释都是本人遇到错误的一些小细节。
class Solution {
public:
void solve_n(vector<vector<string>>&_s,vector<string> & _ss,string & _sss,int _row,int _col,int Leftover,int addr_row_col_[]){//Leftover 剩余棋子
if(Leftover==0){//剩余棋子为零返回
_s.push_back(_ss);
//cout<<"* *"<<endl;
return;
}
//cout<<Leftover<<endl;
bool b=false;
while(_col<(_row+Leftover)){
//判断在addr_row_col_中是否存在,同时判断是否在上一行addr_row_col_[_row-1]的对角线
//不仅上一行的对角线是所有的对角线
//注意递归后恢复此次addr_row_col_里的数值,这个很重要!!!!!!!
//递归后的回溯一定要将某些数值恢复默认值此处还有一个 _col++超过边界string不会报错,然后_sss[Q]
//不会报错,但这是不符合要求的,所以if(_col==_row+Leftover) break;
_col++;
for(int j=0;j<=_row;j++){//只用判断前N行放置的结果
if(_col==addr_row_col_[j]-(_row-j)||_col==addr_row_col_[j]+_row-j){
b=true;
break;
}
if(_col==addr_row_col_[j]){
b=true;
break;
}
}
if(b) {
b=false;
continue;
}
if(_col==_row+Leftover) break;//放置位置虽然满足条件,但_col在棋盘外
addr_row_col_[_row]=_col;//纪录每一行col位置
_sss[_col]='Q';//修改字符串
//cout<<_col<<" "<<_sss<<endl;
_ss.push_back(_sss);//末尾添加字符串
_sss[_col]='.';//改回棋盘
solve_n(_s,_ss,_sss,_row+1,-1,Leftover-1,addr_row_col_);//假设初始棋子位置位与—1列
addr_row_col_[_row]=-2;//恢复此时位置的addr_row_col_
_ss.pop_back();//弹出此时添加的行
}
return;
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> s;
vector<string> ss;
string sss;
int row=0; //行
//int col=-1; //列
int addr_row_col[n];
for(int i=0;i<n;++i){
sss.push_back('.');//初始化sss字符串
addr_row_col[i]=-2;//初始化放置位置,负数即可
}
solve_n(s,ss,sss,row,-1,n,addr_row_col);//递归——回溯,假设初始棋子位置位与—1列
return s;
}
};