深度优先算法DFS(Depth First Search)

一、基本思想

不撞南墙不回头

  1. 为了求得问题的解,先选择某一种可能情况向前探索;
  2. 在探索过程中,一旦发现原来的选择是错误的,就退回一步重新选择,继续向前探索;
  3. 如此反复进行,直至得到解或证明无解。

二、算法原理

深度优先搜索(Depth First Search),是图遍历算法的一种。用一句话概括就是:"一直往下走,走不通回头,换条路再走,直到无路可走"。

假设我们有一个二叉树,共有10个节点,以下是DFS的简单示范:

从根节点开始向下搜索

然后搜索到2号节点

继续不断向深层处的节点搜索,搜索到4号节点

最后搜索到7号节点

当搜索到7号节点后,我们发现无路可走了,因为7号节点是当前这条路径下最深处的节点,因此,我们需要进行回溯操作

当回溯到4号节点时,我们发现4号节点并没有另一条路,也就是说从4号节点向下搜索的话,只能搜索到7号节点,但是可是刚刚才从7号节点回溯上来诶,我们总不可能又搜索到7号,然后又回溯到4号无限下去吧......所以,我们得再次回溯,也就是跳到2号节点上。

当再次跳到2号节点上时,我们发现从2号节点开始,还有另一条路可以走。那我们就走下去!

此时又有两条路可以走,我们先去往8号

走到8号,我们发现又走到头了,那就再对它使用回溯吧!!!

这次我们选择另一条路,走到9号

然后我们发现又双走到头了,因此,再次回溯,从9号跳到5号,再跳到2号,然后再跳到1号(因为5号,2号向下的路我们已经走过了,但我们发现1号节点向下的路还有一条是我们没走过的)

接下来搜索类似,我们走到3号,然后走到6号,然后走到10号

当10号走完后,这颗树的每个节点都被搜索过了,最后回溯到根节点

三、模板

1、C模板

复制代码
int a[510];   //存储每次选出来的数据
int book[510];   //标记是否被访问
int ans = 0; //记录符合条件的次数

void DFS(int cur){
	if(cur == k){ //k个数已经选完,可以进行输出等相关操作 
		for(int i = 0; i < cur; i++){
			printf("%d ", a[i]);
		} 
		ans++;
		return ;
	}
	
	for(int i = 0; i < n; i++){ //遍历 n个数,并从中选择k个数 
		if(!book[i]){ //若没有被访问 
			book[i] = 1; //标记已被访问 
			a[cur] = i;  //选定本数,并加入数组 
			DFS(cur + 1);  //递归,cur+1 
			book[i] = 0;  //释放,标记为没被访问,方便下次引用 
		}
	}
}

2、C++模板

复制代码
vector<int> a; // 记录每次排列 
vector<int> book; //标记是否被访问 

void DFS(int cur, int k, vector<int>& nums){
    if(cur == k){ //k个数已经选完,可以进行输出等相关操作 
        for(int i = 0; i < cur; i++){
			printf("%d ", a[i]);
		} 
        return ;
    }
    for(int i = 0; i < k; i++){ //遍历 n个数,并从中选择k个数 
        if(book[nums[i]] == 0){ //若没有被访问
            a.push_back(nums[i]); //选定本输,并加入数组 
            book[nums[i]] = 1; //标记已被访问 
            DFS(cur + 1, n, nums); //递归,cur+1 
            book[nums[i]] = 0; //释放,标记为没被访问,方便下次引用 
            a.pop_back(); //弹出刚刚标记为未访问的数
        }
    }
}

四、例题(持续更新)

1、例题一(全排列)

设有n个整数的集合{1,2,...,n},从中取出任意r个数进行排列(1<=r<n<=10),试列出所有的排列。

示例:

复制代码
输入:n = 4, r = 3
输出:
1 2 3
1 2 4
1 3 2
1 3 4
1 4 2
1 4 3
2 1 3
2 1 4
2 3 1
2 3 4
2 4 1
2 4 3
3 1 2
3 1 4
3 2 1
3 2 4
3 4 1
3 4 2
4 1 2
4 1 3
4 2 1
4 2 3
4 3 1
4 3 2
24

思路:

1)定义两个数组 a\[\] 与 book\[\] ,其中数组a保存每次的排列数据,数组book用来标记 i 这个数是否被访问;

2)初始化相关数据;

3)递归填数并判断第i个数填入是否合法:

合法:填数,并判断是否已经到达环的终点。如果到达终点,打印结果;否则,继续填下一个 数;

不合法:选择下一种可能。

代码:

复制代码
#include<iostream>

using namespace std;

int n, r, ans;  //r个数进行全排列  ans为排列个数 
int book[510]; //标记是否被访问
int a[510]; //记录每次的排列数据

void DFS(int cur){ //从{1,2,...,n}中取r个数构成的排列
	if(cur == r){ //已经去够r个数 
		for(int i = 0; i < cur; i++){ //循环输出 
			cout << a[i] << ' ';
		}
		cout << endl;
		ans++;  //数量加1 
		return ;
	}
	
	for(int i = 1; i <= n; i++){  //循环遍历保证不漏 
		if(!book[i]){ //若没访问过 
			book[i] = 1; //标记已访问
			a[cur] = i; //i符合条件加入
			DFS(cur + 1); //寻找一个数字 
			book[i] = 0; //回溯:清除标记
		}
	} 
} 

int main(){
	cin >> n >> r;
	DFS(0);
	
	cout << ans << endl;
	return 0; 
}
相关推荐
土司大王6 小时前
LeetCode hot100——对称二叉树
算法·leetcode·职场和发展
sali-tec7 小时前
C# 基于OpenCv的视觉工作流-章106-差值追踪
图像处理·人工智能·opencv·算法·计算机视觉
Navigator_Z7 小时前
LeetCode //C - 1208. Get Equal Substrings Within Budget
c语言·算法·leetcode
手写码匠7 小时前
Dify 多 Agent 工具权限与安全沙箱实战:让智能体“有能力,但不越权“
人工智能·深度学习·算法·aigc
黎阳之光7 小时前
打破堆场感知黑盒:黎阳之光视频孪生,构建港口码头网格化透明管控新体系
大数据·人工智能·算法·安全·数字孪生
大模型码小白8 小时前
AI 对话流性能调优:万级消息的虚拟滚动落地
java·大数据·前端·javascript·人工智能·算法·机器学习
sel_98 小时前
【多轮对话论文导读(三)】多轮对话与Agent论文阅读笔记:用户模拟、轨迹生成与长期记忆
论文阅读·人工智能·笔记·深度学习·算法·机器学习
Asize9 小时前
438. 找到字符串中所有字母异位词
算法
Asize9 小时前
283. 移动零
算法
船厂电气自动化ai大模型11 小时前
AI大模型与数学·第57课 傅里叶全套工具链综合实战:串联级数/连续变换/DFT/FFT,图像、音频、扩散模型完整例题
数据结构·人工智能·深度学习·算法·机器学习