【算法篇-搜索与图论】适合算法入门小白理解的深度优先搜索(DFS )以及解决全排列数字

news2024/12/20 9:50:15

目录

  • 1.什么是深度优先搜索(DFS)
  • 2.结合例子看DFS
    • 2.1 全排列数字
  • 结语

该文章部分内容摘抄自 啊哈磊老师的《啊哈!算法》
一本对算法新手非常友好的书,非常推荐新手去阅读!

1.什么是深度优先搜索(DFS)

Deep First Search(简称DFS)
中文名也就是深度优先搜索

DFS其过程简要来说就是
对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次.

DFS其实是属于图算法中的一种

在这里插入图片描述

首先,这是一个 “图”,我们要把它的每个点都遍历一遍,
沿着一条路一直走,一直到不能走为止,这个过程可以被称为
“深度优先搜索”。
然后,我们的目的是把所有点都走一遍,
当1 -> 2 -> 4 走到无路可走时,退回到2
退回到2时,我们会发现,2处也无路可走,那么就退回到1
然后退回到1后,有路可以走了,走1 -> 3
3处有路可以走,走到5,
就是1 -> 3 -> 5
走的次序就是

在这里插入图片描述

这就是DFS走的结果
深度优先搜索的思想就是

以一个未被访问的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点;当没有为访问过的顶点时,则回到上一个顶点,继续试探访问别的顶点,直到所有的顶点都被访问过。
回到上一个顶点的过程也叫做 “回溯”
“回溯“也是非常重要的过程,我们需要恢复到原来的场景。

具体过程慢慢看下面的代码分析就能明白了。

2.结合例子看DFS

2.1 全排列数字

题目:
在这里插入图片描述

我们来看一下在这个经典的全排列数字的问题。
假如我们没有学过DFS,我们会怎么做?
先思考几分钟。再往下看
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
//你可能已经想出来了,就是这种暴力枚举的方法。
//其实我们的搜索法也是非常暴力的一种方法
//不过是在代码上做了一些优化。
int main()
{
	for(int a = 1;a <= 3 ;a++)
	{
	    for(int b = 1;b <= 3; b++)
	    {
	        for(int c = 1;c <= 3;c++)
	        {
	            if(a != b && a != c && b !=c )
	            {
	                printf("%d %d %d \n",a,b,c);
	            }
	        }
	    }
	}
}
/*1 2 3 
  1 3 2 
  2 1 3 
  2 3 1 
  3 1 2 
  3 2 1*/
下面,我们来看一下,用DFS这道题该怎么做
我们把这个问题形象一点给大家再次介绍。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注:再次强调!以上文字内容摘抄自 啊哈磊老师的《啊哈!算法》
非常感谢有这么一位好的老师,能把复杂的算法给新手小白讲明白。

for(i = 1;i <= n;i++)
{
	a[step] = i;//将i号扑克牌放入到第step个盒子中
}

这里的数组a是用来表示小盒子的,变量step表示当前正处在第step个小盒子面前。a[step] = i;就是将第i号扑克牌,放入到第step个盒子中。
这里有一个问题就是,如果一张扑克牌已经放到别的小盒子中了,那么此时就不能再放入同样的扑克牌到别的盒子中了,因为此时手里已经没有扑克牌了。因此还需要一个数组book来标记哪些牌已经使用了。

for(i = 1;i <= n;i++)
{
	if(book[i] == false) //等于false,表示第i号牌没有被使用过 
	{
		a[step] = i;  //把i号牌放入到第step个盒子中
		book[i] = true;  //把book[i] 设为true,表示已经用过了i号牌
	}
}

我们现在已经处理完第step个小盒子了,接下来需要往下走一步,去处理第step+1个小盒子。
如何处理呢?
处理方法其实和我们刚刚处理第step个小盒子的方法相同。
把它封装成一个函数

void dfs(int step) // 表示站在第step个小盒子面前
{
	for(int i = 1; i <= n;i++)
	{
		if(book[i] == false) // 判断扑克牌是否用过
		{
			a[step] = i; //没用过就把第i号扑克牌放入第step个小盒子
			book[i] = true;//book[i]设为true,表示第i号扑克牌我们已经用过
		}
	}
}

把这个过程变成函数以后,就好处理第step + 1 个盒子了
就是 dfs(step + 1),来看代码

void dfs(int step) // 表示站在第step个小盒子面前
{
	for(int i = 1; i <= n;i++)
	{
		if(book[i] == false) // 判断扑克牌是否用过
		{
			a[step] = i; //没用过就把第i号扑克牌放入第step个小盒子
			book[i] = true;//book[i]设为true,表示第i号扑克牌我们已经用过


			dfs(step + 1);//通过函数递归来实现(函数自己调用自己)
			book[i] = false;
//这里是非常重要的一步,一定要将刚才尝试的扑克牌收回,才能进行下一次尝试
		}
	}
}

book[i] = false;
这一步非常重要,也就是我们上面说的回溯,回溯要恢复到原来的场景。
也就是我们把扑克牌收回,否则无法进行下一次的摆放。

现在还有一个问题,就是什么时候输出一个满足要求的序列呢?
其实当我们处理第n + 1个小盒子的时候(即step = n + 1),说明前n个小盒子已经放好扑克牌了,这里将1~n个小盒子中的扑克牌编号打印出来就可以了。注意!打印完毕之后一定要return,否则程序就会永无止境地进行下去了,也就是要有递归的终止条件。

void dfs(int step) // step 表示现在站在第几个盒子面前
{
	if(step == n + 1) //如果站在第n+1个盒子面前,则表示前n个盒子已经放好扑克牌
	{
	//输出一种排列,即 1 ~ n 号盒子中扑克牌编号
		for(int i = 1;i <= n;i++)
		{
			printf("%d ",a[i]);
		}
		printf("\n");
		return; // 返回之前的一步(最近一次调用dfs的地方)
	}
	for(int i = 1;i <= n;i++)
	{
		if(book[i] == false) // 判断扑克牌i是否已经用过
		{
			a[step] = i; //如果没用过,就把i号牌放在第step个盒子
			book[i] = true;//i号牌记录为已经用过
			dfs(step + 1);//处理第step+1个盒子,函数递归实现
			book[i] = false;//将刚才的扑克牌收回,才能进行下一次尝试
		}
	}
}

完整代码如下

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 10;
int n;
int a[N];//开辟的盒子
bool book[N]; //这里是全局变量,默认为false
void dfs(int step) // step 表示现在站在第几个盒子面前
{
	if(step == n + 1) //如果站在第n+1个盒子面前,则表示前n个盒子已经放好扑克牌
	{
	//输出一种排列,即 1 ~ n 号盒子中扑克牌编号
		for(int i = 1;i <= n;i++)
		{
			printf("%d ",a[i]);
		}
		printf("\n");
		return; // 返回之前的一步(最近一次调用dfs的地方)
	}
	for(int i = 1;i <= n;i++)
	{
		if(book[i] == false) // 判断扑克牌i是否已经用过
		{
			a[step] = i; //如果没用过,就把i号牌放在第step个盒子
			book[i] = true;//i号牌记录为已经用过
			dfs(step + 1);//处理第step+1个盒子,函数递归实现
			book[i] = false;//将刚才的扑克牌收回,才能进行下一次尝试
		}
	}
}
int main()
{
    cin >> n;
    dfs(1);
    return 0;
}

这段简单的例子,核心的代码不超过20行
但是却饱含了DFS的基本模型
理解深度优先搜索关键在于解决“当下该如何做”。
至于“下一步该如何做”则与“当下该如何做是一样的”
比如我们这里写的dfs(step)函数的主要功能就是解决当你在第step个盒子的时候你该怎么办。通常的方法就是把每一种可能都去尝试一遍(一般使用for循环来遍历)。当前这一步解决后便进入下一步dfs(step + 1)。下一步的解决方法和当前这步的解决方法是完全一样的。下面的代码就是深度优先搜索的基本模型


```c
void dfs(int step)
{
	判断边界
	尝试每一种可能for(i = 1;i <= n;i++)
	{
		继续下一步 dfs(step+1);
	}
	返回
}

每一种尝试就是一种“扩展”。每次站在一个盒子面前的时候,其实都有n种扩展方法,但是并不是每种扩展方法都能扩展成功的。

结语

再次感谢啊哈磊老师,能把这些复杂的算法思想讲得如此透彻,为刚接触算法新手小白留了一条路,非常感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【阿里云】短信服务

目录 1. 前置技术&#xff1a;阿里大鱼 1.1 概述 1.2 开通 1.3 签名管理 1.3.1 签名概述 1.3.2 添加签名 1.3.3 使用 1.4 模板管理 1.4.1 模板概述 1.4.2 添加模板 1.4.3 使用 1.5 在线文档 1.5.1 打开在线文档 1.5.2 使用在线文档 1.6 使用工具类发送短信 1.7…

基于混合VNS(变邻域搜索算法)的PSO(粒子群优化算法)的任务分配问题(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

数据分析 | Pandas 200道练习题,每日10道题,学完必成大神(3)

文章目录1.读取本的数据集2.查看数据的前5行3.将salary列的数据转换为最大值和最小值的平均值4.将数据根据学历进行分组计算平均值5.将createTime列转换为月日6.查看所索引&#xff0c;数据类型和内存信息7.查看数值型列的汇总统计8.新增一列根据salary将数据分为三组9.按照sal…

【Day31】力扣算法(超详细思路+注释)[1441. 用栈操作构建数组 ] [621. 任务调度器]

您的点赞&#xff0c;收藏以及关注是对作者最大的鼓励喔 ~~ 刷题打卡&#xff0c;第 三十一 天题目一、1441. 用栈操作构建数组题目二、621. 任务调度器题目一、1441. 用栈操作构建数组 原题链接&#xff1a;1441. 用栈操作构建数组 题目描述&#xff1a; 给你一个数组targe…

5 个 Flutter VSCode 技巧和窍门,你可以马上使用!

5 个 Flutter VSCode 技巧和窍门&#xff0c;你可以马上使用&#xff01; 前言 今天&#xff0c;我将向你展示 5 个非常有用的 Flutter 技巧&#xff0c;你可以立即应用到你的项目中。我不会给你任何软件包或扩展&#xff0c;但非常简单&#xff0c;但非常有用的技巧&#xff0…

【大厂高频真题100题】单词拆分 真题练习第7题 持续更新~

单词拆分 描述: 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例 1: 输入: s = "leetcode", wordDict = ["leet&q…

德邦股份第三季营收80亿:净利2.56亿 京东控制72%股权

雷递网 雷建平 10月28日德邦物流股份有限公司&#xff08;证券代码&#xff1a;603056&#xff0c;证券简称&#xff1a;德邦股份&#xff09;今日发布财报。财报显示&#xff0c;德邦股份2022年前9个月营收为228.17亿元&#xff0c;较上年同期增长1.14%&#xff1b;净利为3.5亿…

springboot+jsp志愿者岗位报名培训系统javaweb

当我知道北京冬奥会申请成功&#xff0c;也刚好是我的毕业&#xff0c;觉得自已需要做点什么&#xff0c;北京冬奥会申请成功觉得自已去做一个志愿者&#xff0c;这样不断丰富了自已的经历&#xff0c;还能给自已在现实生活中上了一课&#xff0c;为了迎合志愿者需求&#xff0…

每日学习06:=和== 和 equals 你学废了吗?

1.赋值运算符 &#xff1a;是赋值运算符。赋是指为变量或常量指定数值的符号。赋值运算符的符号为“”&#xff0c;它是双目运算符&#xff0c;左边的操作数必须是变量&#xff0c;不能是常量或表达式。 赋值运算符的优先级低于算术运算符&#xff0c;结合方向是自右向左&…

Python基础_第4章_Python数据序列(容器)

Python基础_第4章_Python数据序列&#xff08;容器&#xff09; 文章目录Python基础_第4章_Python数据序列&#xff08;容器&#xff09;Python数据序列&#xff08;容器&#xff09;一、作业回顾1、面试题2、报数字&#xff08;数7&#xff09;二、了解字符串1、字符串的定义2…

蓝桥杯备赛(二)

目录 前言&#xff1a; 一、ASC 分析 代码实现 二、 卡片 分析 代码实现 三、 直线 分析 代码实现 四、货物摆放 分析 代码实现 小结&#xff1a; 前言&#xff1a; 在刷题的过程中&#xff0c;发现蓝桥杯的题目和力扣的差别很大。让人有一种不一样的感觉&#xff…

【IO】文件操作基础知识

目录 1.文件的操作&#xff1a; 2.文件内容的读写—数据流&#xff1a; 3.文件操作练习&#xff1a; 1.文件的操作&#xff1a; 文件分为狭义上的文件和广义的文件。狭义上的文件&#xff1a;存储在硬盘上的数据&#xff0c;以“文件”为单位进行组织。文件夹也叫做目录。通…

图第三遍补充(各种算法与力扣)

一、一些补充的概念 如果具有n个结点的图中是一个环&#xff0c;则会有n个不同的生成树&#xff0c;每个生成树有n-1条边 连通、连通图、连通分量&#xff1a;路径&#xff0c;无向图 &#xff0c;极大连通子图为连通分量&#xff0c;边数小于n-1&#xff0c;则图必为非连通图…

Xilinx XC7Z020双核ARM+FPGA开发板试用合集——自定义硬件工程

本期测试板卡是一款基于Xilinx Zynq-7000系列XC7Z010/XC7Z020高性能低功耗处理器设计的异构多核SoC工业级核心板,处理器集成PS端双核ARM Cortex-A9 + PL端Artix-7架构28nm可编程逻辑资源。 下面是测试内容,欢迎查阅。 SD卡启动设置 根据《TLZ7x-EasyEVM-S评估板硬件说明书》…

开心消消乐游戏网页设计作品 学生dreamweaver作业静态HTML网页设计模板 游戏主题网页作业制作

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

有营养的算法笔记(八)

有营养的算法笔记八摆砖块问题数字转换K递增子序列魔法子数组摆砖块问题 1.题目描述 给定一个正数数组arr&#xff0c;其中每个值代表砖块长度。所有砖块等高等宽&#xff0c;只有长度有区别&#xff0c;每一层可以用1块或者2块砖来摆。要求每一层的长度一样 要求必须使用所有…

【阅读笔记】低照度图像增强-《An Integrated Neighborhood Dependent...

本文介绍的是一种比较实用的低照度图像增强算法&#xff0c;选自2004年Tao的一篇论文&#xff0c;名称是《An Integrated Neighborhood Dependent Approach for Nonlinear Enhancement of Color Images 》 概述 图像中暗区图像增强的基本机制是对图像的亮度进行动态范围压缩&…

玩转rancher 2.6之 monitor监控

目录 前言 1. 安装monitor 2. 安装prometheus-webhook-dingtalk 2.1 配置钉钉告警配置文件 2.2 创建钉钉告警模板 2.3 创建dingtalk configmap配置文件 2.4 安装dingtalk 2.5 dingtalk调用方法 3. 配置告警 3.1 配置告警接收者 3.2 配置路由默认告警接收者 4. 测试 前…

初识C++ (三)

初识C 三引用一. 引用的概念代码演示二. 引用特性1. 引用在定义时必须要初始化2. 一个引用可以有多个实体3. 引用一旦引用一个实体&#xff0c;再不能引用其他实体三. 使用场景1. 做参数2. 做返回值内存销毁后空间还在吗&#xff1f;内存销毁后我们还能访问嘛&#xff1f;结论优…

论文写作——ICASSP论文写作及投稿

记录 ICASSP2023 写作投稿过程。小白如何写好并投稿自己的第一篇英文论文&#xff1f;投稿会议时&#xff08;以 ICASSP2023 为例&#xff09;有哪些需要关注的信息以及注意事项&#xff1f;论文写作必备软件有哪些&#xff1f;论文书写关注点有哪些&#xff1f;论文格式与排版…