算法模版:暴力搜索之DFS

简介: 算法模版:暴力搜索之DFS

前言


唤我沈七就行。

又是拖更的两周~

因为开学将至,学校竞赛班也要在开学前的月底来一场测试,所以我就加快了学习算法的进度,最近两周涉猎了DFS、BFS、背包DP、线性DP。也整理了不少笔记,很快就会陆续更新啦~


今天带来的是骗分神器–DFS


基本概念


DFS:是Depth First Search的简称 ,即深度优先搜索算法:

是一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。


当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。


DFS是通过递归来实现的,也就是函数自己调用自己。

所以通俗的说DFS通过递归枚举所有情况,然后从中找到与题设相符的方案。

因为要枚举所以情况属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。

所以DFS不算是最有效率的算法,但一定是考虑情况最全面的算法。


算法思想


回溯法是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。

但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

回溯是DFS最精妙的一步,在算法模板中往往体现在恢复现场。

即在调用完函数自身后,恢复初始状态。

这是因为DFS要枚举所有情况,而枚举方式不是想BFS那样一层一层的,而是一条路走到尾,他每走一步都需要在走的路上做上标记,防止重复走同一条路。

如果没路了,再通过回溯,走下条路。而回溯在这里的作用就是按原路返回,但是因为路上已经做了标记,所以回溯其实就是撤销上一步做的标记(恢复现场)。不然是没办法返回走下一条路的。


如果不理解的没关系,我当初学的时候也是懵懵懂懂,先接着往下看~


常用模板


void dfs(int step)
{
        判断边界//判断是否符合条件
        {
            相应操作
        }
        枚举每一种可能
        {
               标记 //防止多次重复枚举同一个方案
               继续下一步dfs(step+1)
               恢复初始状态(回溯的时候要用到)//恢复现场
               //这就是DFS的精髓之处
               //为的就是不影响下一种方案的枚举
        }
}


三种枚举方式


DFS通常有三种枚举方式,接下来我们一一来介绍


指数型枚举


从 1∼n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案


分析: 从1~n依次考虑 选 和 不选 两种情况。 一共 n 个数,每个数有 2 种情况。总共方案数为 2的n次方。所以被称为指数型枚举。


详细的解释都在注释里


const int N = 1e1 + 6; 定义一个常量N
int n;
int st[N];  记录每个位置当前的状态:0表示还没考虑,1表示选它,2表示不选它
void dfs(int u)  枚举的第几个数字
{
    if(u > n) {  终止条件,因为题目要求一个就n个数 所以只有 u>n 就输出枚举的方案
        for(int i = 1; i <= n; i++)
        if(st[i] == 1) 
        printf("%d ", i);
        puts("");
        return;
    }
    st[u] = 1;   选它的分支
    dfs(u + 1);
    st[u] = 0;   恢复现场,以便进行下一个分支
    st[u] = 2;   不选它的分支
    dfs(u + 1);
    st[u] = 0;   恢复现场
}
int main(void)
{
    scanf("%d", &n);
    dfs(1);
    return 0;
}


排列型枚举


把 1∼n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序。


分析:依次枚举 1~n数 放到哪个位置,排列问题需要考虑顺序,需要book数组来判重。


const int N = 10;
int st[N]; 存储方案
bool book[N]; 标记数字是否被用过,true表示被用过,false表示没被用过
定义在里全局变量,所以现在book数组都是false 表示都没被用过
int n;
void dfs(int u){ 当前枚举第u位
    if(u > n){
        for(int i = 1; i <= n; i ++) 
        printf("%d ", st[i]); 打印方案
        puts("");
        return ;
    }
    for(int i = 1; i <= n; i ++){ 依次枚举每个数
        if(!book[i]) 如果当前数没被用过
        {        
            st[u] = i;       在第u位是i
            book[i] = true;  标记用过
            dfs(u + 1);  递归到下一位
            恢复现场,以便回溯其他情况
            st[u] = 0;  可省略 因为写不写都会被 st[u]=i; 这一层给覆盖掉
            book[i] = false;  不可省 
        }
    }
}
int main(){
    scanf("%d", &n);
    dfs(1);
    return 0;
}


组合型枚举


从 1∼n 这 n 个整数中随机选出 m 个,按字典序输出所有可能的选择方案。


组合问题和排列问题不同,不需要考虑顺序,即 1234 和 4321 都是一种组合.

因为要按字典序输出,所以需要从上一次枚举的数开始来依次枚举,控制局部枚举的数,使得新枚举的数比之前的大。

组合问题不需要考虑顺序,需要x来记录上一次的枚举的数。这样也就可以保证同一种组合只有一种顺序被打印。

因为是从上一次枚举的数开始枚举所以不会保存选用重复数字, 所以不需要定义去重数组book。


int n,m;
int cnt[30]; 记录方案
void dfs(int u,int x){  u 记录枚举了几位 x记录了枚举了到了几
  if(u>m) {  边界
  for(int i=1;i<=n;i++)
  cout<<cnt[i]<<" ";
  puts("");  换行
  return;
  }
  for(int i=x;i<=n;i++) 从x开始枚举
  {
        cnt[u]=i;
        dfs(u+1,i+1);
        cnt[u]=0; 恢复现场  
  }
}
int main()
{
  cin>>n>>m;
  dfs(1,1);
  return 0; 
}


完结散花


ok以上就是对 暴力搜索之DFS 的全部讲解啦,很感谢你能看到这儿啦。如果有遗漏、错误或者有更加通俗易懂的讲解,欢迎小伙伴私信我,我后期再补充完善。


题目练习


检验知识是否学会当然是不断刷题啦,下面我给出一部分DFS相关的一些经典题目。

后续如果我有时间就更新这部分知识的题解,到时候就可以配套学习啦。

N皇后

八皇后

全排列问题


参考文章


参考文献

https://blog.csdn.net/weixin_43272781/article/details


相关文章
|
2月前
|
机器学习/深度学习 算法 C++
【DFS/回溯算法】2016年蓝桥杯真题之路径之谜详解
题目要求根据城堡北墙和西墙箭靶上的箭数,推断骑士从西北角到东南角的唯一路径。每步移动时向正北和正西各射一箭,同一格不重复经过。通过DFS回溯模拟“拔箭”过程,验证路径合法性。已知箭数约束路径唯一,最终按编号输出行走顺序。
|
3月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
244 5
|
3月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
187 0
|
2月前
|
算法 数据可视化 测试技术
HNSW算法实战:用分层图索引替换k-NN暴力搜索
HNSW是一种高效向量检索算法,通过分层图结构实现近似最近邻的对数时间搜索,显著降低查询延迟。相比暴力搜索,它在保持高召回率的同时,将性能提升数十倍,广泛应用于大规模RAG系统。
227 10
HNSW算法实战:用分层图索引替换k-NN暴力搜索
|
4月前
|
机器学习/深度学习 算法 文件存储
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
神经架构搜索(NAS)正被广泛应用于大模型及语言/视觉模型设计,如LangVision-LoRA-NAS、Jet-Nemotron等。本文回顾NAS核心技术,解析其自动化设计原理,探讨强化学习、进化算法与梯度方法的应用与差异,揭示NAS在大模型时代的潜力与挑战。
1145 6
神经架构搜索NAS详解:三种核心算法原理与Python实战代码
|
8月前
|
人工智能 自然语言处理 算法
阿里云 AI 搜索开放平台:从算法到业务——AI 搜索驱动企业智能化升级
本文介绍了阿里云 AI 搜索开放平台的技术的特点及其在各行业的应用。
891 3
|
3月前
|
机器学习/深度学习 算法 机器人
【机器人路径规划】基于深度优先搜索(Depth-First-Search,DFS)算法的机器人路径规划(Python代码实现)
【机器人路径规划】基于深度优先搜索(Depth-First-Search,DFS)算法的机器人路径规划(Python代码实现)
277 3
|
3月前
|
存储 算法 数据可视化
基于禁忌搜索算法的TSP问题最优路径搜索matlab仿真
本程序基于禁忌搜索算法解决旅行商问题(TSP),旨在寻找访问多个城市的最短路径。使用 MATLAB 2022A 编写,包含城市坐标生成、路径优化及结果可视化功能。通过禁忌列表、禁忌长度与藐视准则等机制,提升搜索效率与解的质量,适用于物流配送、路径规划等场景。
|
4月前
|
机器学习/深度学习 并行计算 算法
MATLAB实现利用禁忌搜索算法解决基站选址问题
MATLAB实现利用禁忌搜索算法解决基站选址问题
176 0
|
5月前
|
存储 搜索推荐 算法
加密算法、排序算法、字符串处理及搜索算法详解
本文涵盖四大类核心技术知识。加密算法部分介绍了对称加密(如 AES)、非对称加密(如 RSA)、哈希摘要(如 SHA-2)、签名算法的特点及密码存储方案(加盐、BCrypt 等)。 排序算法部分分类讲解了比较排序(冒泡、选择、插入、归并、快排、堆排序)和非比较排序(计数、桶、基数排序)的时间复杂度、适用场景及实现思路,强调混合排序的工业应用。 字符串处理部分包括字符串反转的双指针法,及项目中用正则进行表单校验、网页爬取、日志处理的实例。 搜索算法部分详解了二分查找的实现(双指针与中间索引计算)和回溯算法的概念(递归 + 剪枝),以 N 皇后问题为例说明回溯应用。内容全面覆盖算法原理与实践
202 0

热门文章

最新文章