dfs算法

DFS 的基本思想是从起始节点开始,沿着一条路径尽可能深地访问,直到到达最深处,然后回溯到前一个节点,再尝试探索其他路径。这个过程会递归进行,直到所有的节点都被访问过。

在DFS中,每个节点都有三种状态:未访问、已访问但未探索完所有相邻节点、已访问且已探索完所有相邻节点。算法会确保每个节点都会被访问,并且在需要时进行回溯。

DFS常用于解决图相关的问题,如寻找路径、检测连通性、拓扑排序等。它也可以应用在树结构上,因为树可以看作是一种特殊的图。

具体步骤包括:

具体来说,这些变量在N皇后问题的解法中有以下用途:

  1. 选择一个起始节点。
  2. 访问该节点并标记为已访问。
  3. 对于当前节点的每个未访问的相邻节点,重复以上步骤。
  4. 当无法继续深入时,回溯到前一个节点,重复步骤3,直到所有节点都被访问过。
  5. 例题 N皇后问题
  6. 题目描述

    在 N×N 的方格棋盘放置了 N 个皇后,使得它们不相互攻击(即任意 22 个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成 4545 角的斜线上。你的任务是,对于给定的 N,求出有多少种合法的放置方法。

    输入描述

    输入中有一个正整数 N≤10,表示棋盘和皇后的数量

    输出描述

    为一个正整数,表示对应输入行的皇后的不同放置数量。

    输入输出样例

    示例 1

    输入

    #include<bits/stdc++.h>
    using namespace std;
    int a[11][11];
    int ans = 0; int n;
    bool check(int deep,int m){
        for(int k = 0; k < n ; ++ k){
            if(a[k][m]) return false;
        }
        // 检查所有方向以判断皇后是否会攻击
        //下方还没有放置皇后,所以不用检查
        for(int i = 1; i <= deep; i++) {
            if(a[deep - i][m]) return false; // 检查上方
            if(m - i >= 0 && a[deep - i][m - i]) return false; // 检查左上方
            if(m + i < n && a[deep - i][m + i]) return false; // 检查右上方
        }
        return true;
    }
    void dfs(int deep){
        if(deep == n){
            ans++;
            return;
        }
        for(int i = 0; i < n ; ++ i){
            if(check(deep,i)){
                a[deep][i] = 1; // 放置皇后
                dfs(deep+1);
                a[deep][i] = 0; // 移除皇后
            }
        }
    }
    int main(){
        cin>>n;
        dfs(0);
        cout<<ans;
        return 0;
    }

    代码解析:

  7. deep

    • deep 表示当前递归深度,即当前处理的行数。
    • dfs 函数中,通过递归的方式,每次处理一行,deep 表示当前处理的是第几行。
  8. m

    • m 表示当前处理的列数。
    • dfs 函数中,通过循环遍历当前行的每一列,m 表示当前处理的是第几列。
  9. deep 用于表示递归的深度,即处理的是棋盘的第几行。
  10. m 用于表示当前处理的列,通过循环遍历每一列。
  11. k 用于表示当前检查的行,通过循环遍历每一行,检查是否有其他皇后存在。
    • k

      • k 表示循环变量,用于遍历棋盘的行。
      • check 函数中,通过循环遍历所有行,k 表示当前遍历的行。
    • a[11][11]:表示一个11×11的二维数组,用于表示棋盘,其中的元素 a[i][j] 表示第 i 行第 j 列的格子,1表示放置了皇后,0表示没有放置皇后。
    • ans:记录找到的合法解的数量。
    • n:表示N皇后问题中棋盘的大小,即N。
    • bool check(int deep,int m){
    • 该函数用于检查在第 deep 行第 m 列放置皇后是否合法。
    • 首先检查同一列是否有其他皇后,然后检查所有方向以确保没有其他皇后攻击。
    • int deep:表示当前处理的行数。
    • int m:表示当前处理的列数。
    • for(int k = 0; k < n ; ++ k):这是一个循环,遍历所有的行 k(从0到 n-1)。

      • int k 是循环变量,代表当前遍历的行。
      • k < n 是循环的终止条件,确保遍历所有行。
      • ++k 是每次循环迭代后,将 k 的值递增1。
    • if(a[k][m]) return false;:在循环体内,检查当前列 m 上的第 k 行是否已经存在其他皇后(a[k][m] 是否为1)。

      • 如果 a[k][m] 为1,表示当前列上的某一行已经有皇后,说明不能在当前位置放置皇后。
      • 因此,函数返回 false,表示不合法。
    • 如果循环结束后没有触发 return false;,则说明在当前列 m 上没有其他皇后,可以在该列放置皇后,函数返回 true,表示合法。

    • a[deep - i][m]:表示在当前行 deep 上方第 i 行、第 m 列的位置是否已经放置了皇后。

      • deep - i 表示在当前行 deep 的上方第 i 行。
      • m 表示当前列。
    • if(a[deep - i][m]):通过判断 a[deep - i][m] 是否为1,即在上方是否存在其他皇后。

  12. return false;:如果上方已经存在其他皇后,则返回 false,表示当前位置 (deep, m) 不合法,不能放置皇后。

  13. deep == n:判断当前递归的深度是否等于棋盘的大小。

  14. 如果等于,说明已经成功放置了 n 个皇后,即找到了一个符合条件的布局。
  15. 进入条件成立的分支。
  16. check(deep, i):调用 check 函数,检查在当前行 deep、列 i 的位置是否可以放置皇后。

    • 如果返回 true,表示可以放置皇后;如果返回 false,表示不能放置皇后。
  17. a[deep][i] = 1;:如果当前位置可以放置皇后,则将二维数组 a 中的相应位置置为1,表示在当前行 deep、列 i 放置了皇后。

  18. dfs(deep+1);:递归调用 dfs 函数,处理下一行(深度+1)。

    这是N皇后问题解法的核心思想,通过递归深度优先搜索,逐行放置皇后。
  19. a[deep][i] = 0;:在递归返回后,表示在当前行 deep、列 i 的位置已经处理完毕,需要进行回溯操作,将之前放置的皇后移除,以尝试其他的列。

    • 将二维数组 a 中的相应位置置为0,表示移除了在当前行 deep、列 i 的皇后。
    • 这个检查是为了确保在当前位置 (deep, m) 的上方没有其他皇后,因为在N皇后问题中,皇后不能互相攻击,所以要检查同一列和同一斜线上是否已经存在其他皇后。这一部分是用于检查同一列的,而在之前的检查函数中,也包含了对斜线的检查。

      这个过程会不断地递归调用,深度优先搜索所有可能的布局,通过回溯操作,尝试不同的列,直到找到所有合法的N皇后布局。整个算法的核心在于递归搜索和回溯,确保不漏掉任何可能的解。

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DFS算法深度优先搜索算法,Depth-First Search)是一种常用的图搜索算法,用于遍历或搜索图或树的所有节点。DFS算法通过递归的方式实现,在搜索过程中优先探索深度,直到到达叶节点再回溯。 在MATLAB中实现DFS算法,可以采用如下步骤: 1. 创建一个函数,用于实现DFS算法。命名为dfs。 2. 设置输入参数,例如起始节点和目标节点。 3. 初始化一个栈数据结构,用于保存待搜索的节点。 4. 初始化一个集合,用于保存已访问的节点。 5. 将起始节点压入栈中,并标记为已访问。 6. 当栈不为空时,执行以下步骤: a. 弹出栈顶节点,将其标记为已访问。 b. 如果当前节点是目标节点,则搜索完成,返回。 c. 如果当前节点不是目标节点,则获取其所有邻接节点。 d. 遍历邻接节点: - 如果邻接节点没有被访问过,则压入栈中,并标记为已访问。 e. 重复步骤6直到栈为空。 7. 如果栈为空仍未找到目标节点,则搜索失败,返回。 使用DFS算法可以解决很多与图相关的问题,例如寻找图中路径,判断图的连通性等。在实际应用中,可以根据具体的问题进行相应的修改和优化,以适应不同的需求。 需要注意的是,在实际编写代码时,应该考虑避免重复访问节点,避免死循环,以及处理异常情况。另外,对于复杂的图结构,可能需要使用其他数据结构或算法进行优化,以提高搜索效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值