题解 | #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;
}
以上写的注释挺多的,就不详细 的单独介绍了。

#算法题#
全部评论

相关推荐

点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务