深度优先搜索汇总

常用英文

最近公共祖先(Lowest Common Ancestor,简称LCA)
posterity,英语单词,主要用作名词,作名词时译为“子孙,后裔;后代”。

什么是深度优先搜索

深度优先搜索,Depth First Search, 简称DFS。它从初始节点出发,按预定的顺序扩展到下一个节点,然后从下一节点出发继续扩展新的节点,不断递归执行这个过程,直到某个节点不能再扩展下一个节点为止。此时,则返回上一个节点重新寻找一个新的扩展节点。如此搜索下去,直到找到目标节点,或者搜索完所有节点为止。
通俗的说:
每个节点都有选择类表,如果列表为空,则结束。否则依次DFS(x) , x ∈ \in 选择列表。节点中间的数字就是DFS序(时间戳)
在这里插入图片描述
某个节点为cur,它的任意祖先节点为anc,任意后代为pos。
深度优先有如下性质:
一,当DFS(cur)没有开始执行时,DFS(pos)一定没有开始执行。
二,当DFS(cur)执行结束时,DFS(pos)一定执行结束。
三,如果cur是长子节点,则DFS(cur)结束后。DFS(anc)正在执行,DFS(pos)已经执行结束。其它节点,都没有开始执行。
四,当前节点,可能是后代节点的前置条件,比如: 求层次(leve)。后代节点也可能是当前节点的前置条件,如:求后代数量。
五,DFS(cur)时的DFS序为time1 ,结束时的DFS序为time2。 则DFS序为[time1,time2)的节点    ⟺    \iff cur及cur的后代。

经典应用

无向图的DFS。需要cur节点parent,当next == parent 是忽略,否则无需循环{cur,parent,cur,parent ⋯ \cdots }
有向图,一般不需要,因为大部分情况是无环图。

封装类

枚举

CEnumNeiBo 枚举邻接点,如果有环,以第一次访问为准。CEnumChild 枚举孩子、无环、无向图。

class IDFSEnum
{
public:
	virtual void Enum(int cur, std::function<void(int)> fun) =0;
	virtual int NodeCount() = 0;
	virtual void Clear() = 0;
 };

class CEnumNeiBo : public IDFSEnum
{
public:
	CEnumNeiBo(const vector<vector<int>>& vNeiBo) :m_vNeiBo(vNeiBo) {
		Clear();
	}
	virtual void Clear() override{ m_vVisit.assign(m_vNeiBo.size(), false); };
protected:
	virtual void Enum(int cur, std::function<void(int)> fun) override {
		m_vVisit[cur] = true;
		for (const auto& next : m_vNeiBo[cur]) {
			if (m_vVisit[next]) { continue; }
			fun(next);
		}
	}
	virtual int NodeCount() { return m_vNeiBo.size(); };
	const vector<vector<int>>& m_vNeiBo;
	vector<int> m_vVisit;
};

class CEnumChild : public IDFSEnum
{
public:
	CEnumChild(const vector<vector<int>>& vChild) :m_vChild(vChild) {}
protected:
	virtual void Enum(int cur, std::function<void(int)> fun) override {
		for (const auto& next : m_vChild[cur]) {fun(next);}
	}
	virtual int NodeCount() { return m_vChild.size(); };
	virtual void Clear() override {};
	const vector<vector<int>>& m_vChild;
};

枚举各节点的孩子

class CDFSChild
{
public:
	const vector<vector<int>>& DFSChild(IDFSEnum& dfsEnum, int root) {
		dfsEnum.Clear();
		m_vChild.resize(dfsEnum.NodeCount());
		DFS(dfsEnum, root);
		return m_vChild;
	};
protected:
	void DFS(IDFSEnum& dfsEnum, int cur) {
		dfsEnum.Enum(cur, [&](int next) {m_vChild[cur].emplace_back(next); DFS(dfsEnum, next); });
	}
	vector<vector<int>> m_vChild;
};

计算各节点层次

class CDFSLeve 
{
public:
	vector<int>& DFSLeve(IDFSEnum& dfsEnum,int root) {
		dfsEnum.Clear();
		m_vLeve.assign(dfsEnum.NodeCount(), -1);
		m_vLeve[root] = 0;
		DFS(dfsEnum,root);
		return m_vLeve;
	}
protected:
	void DFS(IDFSEnum& dfsEnum, int cur) {
		dfsEnum.Enum(cur, [&](int next) {m_vLeve[next] = m_vLeve[cur] + 1; DFS(dfsEnum, next); });	}
	vector<int> m_vLeve;
};

暴力计算树直径

class CDFSForDiameter 
{
public:
	
	int DFSDiameter(IDFSEnum& dfsEnum, int root) {
		dfsEnum.Clear();
		m_iRet = 1;
		DFS(dfsEnum, root);
		return m_iRet;
	}
protected:
	int m_iRet = 1;//记录树的直径,0个节点的树会出错。
	int DFS(IDFSEnum& dfsEnum,int cur) {
		int left = 0;
		dfsEnum.Enum(cur, [&](int next) {
			auto right = DFS(dfsEnum,next);
			m_iRet = max(m_iRet, left + right + 1);
			left = max(left, right);
			});
		return left + 1;
	}
};

题解

无向树路径难度分
【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和2238
【图论】【树形dp】【深度优先搜索】2538. 最大价值和与最小价值和的差值2397
【树】【图论】【树路径】【深度优先搜索】2867. 统计树中的合法路径数目2428
C++深度优先搜索(DFS)算法的应用:2791树中可以形成回文的路径数2677
无向图难度分
【深度优先搜索 图论】:2925在树上执行操作以后得到的最大分数1939
【深度优先搜索】【树】【图论】2973. 树中每个节点放置的金币数目2276
【图论】【状态压缩】【树】【深度优先搜索】1617. 统计子树中城市之间最大距离2308
C++深度优先(DFS)算法的应用:2920收集所有金币可获得的最大积分2350
【树】【异或】【深度优先】【DFS时间戳】2322. 从树中删除边的最小分数2391
【深度优先搜索】【树】【C++算法】2003. 每棵子树内缺失的最小基因值2415
【树】【因子数】【数论】【深度优先搜索】2440. 创建价值相同的连通块2460
【动态规划】【树形dp】【深度优先搜索】LCP 26. 导航装置
有向图难度分
【归并排序】【图论】【动态规划】【 深度优先搜索】1569将子数组重新排序得到同一个二叉搜索树的方案数2288
【深度优先】LeetCode1932:合并多棵二叉搜索树2483
【深度优先搜索】【树】【有向图】【推荐】685. 冗余连接 II
其它难度分
【剪枝】【广度优先】【深度优先】488祖玛游戏
【深度优先搜索】【组合数学】【动态规划】1467.两个盒子中球的颜色数相同的概率2356

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

  • 46
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 41
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 41
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闻缺陷则喜何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值