简述深度优先搜索

推荐访问个人博客,以获得更好的阅读体验
地址:https://www.cristime.top/index.php/archives/8/

一、深度优先搜索是什么

在一个求解问题答案的过程中,有几种求解的方法。最为暴力的就是枚举法。枚举法枚举每一个答案即会产生一个状态,这些状态就会构成一棵解答树。当然,对于大多数题目而言,这些状态大多是无用的,这也就决定了枚举法的低效。

那么,难道就没有方法进行优化了吗?

答案是有的。因为枚举法产生了太多无用状态,所以我们就应该从解答树中去除这些无用的状态。这种方法被称作剪枝。搜索就是剪枝的一种方法。

既然弄清楚了什么是搜索,那么深度优先搜索又是什么呢?

上文介绍了解答树的概念。我们知道,遍历一棵树有两种方式,一种为层次遍历(通常也被称为广度 / 宽度优先遍历);另一种为递归遍历(通常也被称为深度优先遍历)。于是可以得到,递归遍历解答树的方法被称为深度优先搜索,而层次遍历解答树的方法被称为广度 / 宽度优先搜索。

二、深度优先搜索的应用题型

深度优先搜索的应用非常广泛 (也被称为骗分神器)。大多数暴力枚举的题目都可以用深度优先搜索来优化。另外,还有一些问题需要使用回溯法,这种题型非常适合用深度优先搜索来完成。

三、深度优先搜索伪代码

void dfs(一些必要的参数) {    // 深搜英文缩写为 dfs
    if (到达递归终点) {
        比较是否为最优解
        return;
    }
    进行一些操作
    dfs(参数); // 进行下一轮搜索
}

四、例题

洛谷 P1706 全排列问题

这是一道非常简单的深搜应用。代码如下

bool vis[N];  // 访问标记数组
int a[N];     // 排列数组,按顺序储存当前搜索结果

void dfs(int step) {
  if (step == n + 1) {  // 边界
    for (int i = 1; i <= n; i++) {
      cout << setw(5) << a[i];
    }
    cout << endl;
    return;
  }
  for (int i = 1; i <= n; i++) {
    if (vis[i] == 0) {
      vis[i] = 1;
      a[step] = i;
      dfs(step + 1);
      vis[i] = 0;
    }
  }
  return;
}
// 代码来自 OI-Wiki

参考资料:

posted @ 2021-06-06 01:31  Cristime  阅读(914)  评论(0编辑  收藏  举报