题解 | #N皇后问题#
N皇后问题
https://www.nowcoder.com/practice/c76408782512486d91eea181107293b6
2022.0902算法第49题N皇后问题
N皇后问题难在哪,我觉着是题目叙述的方式不好理解,又或者这样的描述让问题看起来更加复杂
刚开始也是不会,看完解析之后发现,和递归回溯的模板是一致的
例如和排列问题作比较,就相当于,网格里每行放置 的都是1234等数字
然后每行选取一个数组组成全排列,列也不能重复;
此时没有对角线这个约束条件。
这样一想,是不是觉着两者十分的相似。
也就是每次循环的对象从一堆数字变成了一行网格。
这个思路大致理解之后,细节还是有一些问题存在的
比如对角线如何判断,有时候就不能想那么具体,想的太具体反而会影响思路
刚开始想着这个问题,感觉好复杂,完全无法下手。
看了答案觉着仔细想想或许能想出来。
主要思路就是:
每行选择一个位置,确保位置有效,递归寻找每行的有效位置,回溯寻找其他所有有效位置。
//设置全局变量,记录N皇后的摆放个数 int count=0; //判断当前位置是否满足条件,不同行,不同列也不在同一条斜线上 //注意,这里的参数需要已经保存的路径path,以及当前的行列 bool isOK(vector<int> &path,int row,int col){ //遍历之前的行,判断每行里面是否有和当前位置冲突的皇后存在, //如果有,则当前位置不能放置皇后,返回false for(int i=0;i<row;i++){ //这里只需要判断不同列的要求,因为当前行还没有放置元素 //而且递归回溯调用确保每行只选取一个皇后 //此外需要判断两条斜对角线上是否存在皇后 //两条对角线上的元素分别和相等,以及差值相等,据此可以判断对角线元素 if(col==path[i]||i+path[i]==row+col||i-path[i]==row-col) return false; } //当循环结束依然没有返回时,说明之前行的皇后与当前位置不冲突,返回true return true; } //递归回溯操作,每次一行(一层,深度+1) //此时的参数,需要传递已经保存的行列位置 //以及网格的大小和当前行,用于递归的跳出,并进行下一次递归 //这里的row和组合里的start作用挺相似的,不对 //感觉这里的row是可以省略的,和排列问题里的deepth是相似的 //row可以使用path.size()代替, void dfs(vector<int> &path,int n){ //递归终止条件,当深度到最后一行时,说明此时完成了一次摆放方式 //计数+1,直接返回,也可以使用path的大小判断 if(path.size()==n){ count++; return ; } //for循环遍历path.size()行的列元素, //也就是在path.size()行选取有效的位置 for(int i=0;i<n;i++){ //判断当前位置(path.size(),i)是否为有效位置 //如果不是则选择下一列继续测试,直到找到有效位置 //如果全部位置都不合适,就不会进行下一层的搜索,直接返回上一层继续循环 //这里循环结束也能跳出递归 if(!isOK(path,path.size(),i)){ continue; } //将找到的合适位置存储起来,其中下标表示行数,值表示列数 path.push_back(i); //递归进入下一次 dfs(path,n); //回溯操作 path.pop_back(); } } int Nqueen(int n) { //这个变量用于存储每行中选取的列数值 //形象点描述就是每层选的数值 vector<int> path; //调用递归函数 dfs(path, n); //返回结果 return count; }以上写的注释挺多的,就不详细 的单独介绍了。