Bootstrap

C++深度优先搜索(DFS)详解

今天我带给大家的是深度优先搜索,全拼:Depth First Search,简写DFS


开始了哦,认真看

认识DFS

DFS的基本思想就是递归
其过程为沿着每一个可能的路径向下进行搜索,直到不能再深入为止,并且每一个节点只能访问一次
如果还不理解就看下面
如果还不理解就看上图
懂了吗,懂了就继续往下看吧!

经典题型

1.迷宫 信息学奥赛一本通1215
迷宫链接 可以试着去看题
分析思路:
用朴素的办法:就是用两个下标去判断,从而存在一个数组中
用深搜的办法:定义一个递归,下标在变,到了就返回
知识点
做上面相似的一些题,都会用上一些知识
首先,我们需要一个方向数组,好来判断前面方向可不可以走
因为深搜的性质就是暴力枚举

方向数组怎么定义呢?
用数组,例如迷宫其实就是可以上下所有
如果向右那么x坐标轴就增加1,y坐标轴不变
如果向上那么x坐标轴就不变,y坐标轴增加1
如果向左那么x坐标轴就增加-1,y坐标轴不变
如果向下那么x坐标轴就不变,y坐标轴增加-1
那么就是

int dx[] = {0,0,1,-1}
int dy[] = {1,-1,0,0}

记得一定要对应上
有了方向数组,基本就可以了
但是要注意,还得判断一下这个位置被走过没有,不然就会卡死在这喽
代码

#include<iostream>
#include<cstring>
using namespace std;
int t,n,sx,sy,ex,ey; //起点位置和终点位置
char ans[101][101]; //存储当前位置是否可以走
bool v[101][101],flag; //判断这个位置走没走过,flag就是这次是否能走到终点
int dx[] = {0,0,1,-1}; //方向数组
int dy[] = {1,-1,0,0};
void dfs(int x,int y){ //深度优先搜索函数
	if(x == ex && y == ey){ //边界条件,到终点那么将flag变为是,并且返回
		flag = true;
		return;
	}
	for(int i = 0; i < 4; i++){
		int nx = dx[i] + x; // nx是预计下一个x坐标的位置
		int ny = dy[i] + y; // ny是预计下一个y坐标的位置
		if(ans[nx][ny] == '#') continue; //如果预测位置不能通行,那就换一个
		if(v[nx][ny]) continue; // 如果预计位置被走过,那也换一个
		if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue; //不能超边界
		v[nx][ny] = 1; //可以走,那么就将当前位置赋值为可走
		dfs(nx,ny); //出发去这个位置
	} 
}
int main(){
	cin >> t;
	while(t--){
		cin >> n;
		for(int i = 0; i < n; i++){
			for(int j = 0; j < n; j++){
				cin >> ans[i][j];
			}
		}
		cin >> sx >> sy >> ex >> ey;
		v[sx][sy] = 1;//将起点赋值为被走过
		flag = false;//默认不能走到终点
		memset(v,0,sizeof(v)); //每次判断完都要将v数组所有元素赋值为没走过
		dfs(sx,sy);
		cout << (flag?"YES":"NO") << endl; //如果flag是对,那么就输出YES,否则输出NO
	}
	return 0;
}

看明白了吗?
去练习一下马走日吧,代码可以发在评论区哦,我在的时候可以看一下
2.全排列 信息学奥赛一本通1199
全排列链接 可以试着去看题
分析思路:
用朴素的办法:将总字符串拆开存在字符数组中,然后排序,用循环输出答案
用深搜的办法:定义一个下表与数组,将分开的答案存在里面,最终输出
知识点
回溯:把一个物品使用完后,再赋值,然后使用
这道题就需要回溯,因为一个字符是需要用很多次的,而不是一次,所以要回溯
代码

#include<iostream>
#include<cstring>
using namespace std;
char a[101],b[101]; //输入数组与存储数组
bool v[101]; //判断字符是否被使用过
void dfs(int step){ //step是当前已经放了几个字符
	if(step == strlen(a)){ //如果已经满了,就不放了,输出
		cout << b << endl;
		return; 
	}
	for(int i = 0; i < strlen(a); i++){ //没有满,那么就开始装第step个字符
		if(!v[a[i]]){ //判断字符是否被使用过
			v[a[i]] = 1;  //使用当前字符,所以要赋值为使用过
			b[step] = a[i]; // 给b数组赋值
			dfs(step + 1); // 赋值下一位
			v[a[i]] = 0; // 回溯
		}
	}
}
int main(){
	cin >> a;
	dfs(0); // 已使用0个字符,所以传参为0
	return 0;
}

学会了吗?
练习一下组合的输出
代码可以发在评论区

总结

深度优先搜索(DFS)的性质是暴力枚举,基本思想是递归

你们期待我的下一篇文章吗?期待就动一动你的小鼠标,为我点个赞,加个关注吧!!!

;