DFS深搜BFS广搜方法 及 常见bug解释

       

目录

        一.深搜:

                1.深搜的定义:

                2.深搜的步骤:

                  3.例题详解:

二 .广搜

        1.广搜含义:

        2.广搜步骤:

        3.广搜例题:


        当我们需要在一个范围内逐步的寻找某个特定的元素,就需要使用搜索方法。 今天主要讲解深搜广搜

        一.深搜:

                1.深搜的定义:

                深搜就是按一种方式走到底。如果类比为战争,深搜就是派出一名先锋,杀入敌人内部,进行斩首行动,所以他的运动方向是单一的,不能多个方向同时进行,他一头扎进去,一次性把敌人的版图走完,要么找到目标,要么失败。所以深搜的精髓在于按一定顺序前进和发现路走不通时进行回溯。  回溯的定义就是退到上一个状态,并向其他方向走。如果继续用上面的例子,就相当于战士在一个分岔口向左拐后发现是一个死胡同,就需要回到上一个分岔口,然后向右拐。

                2.深搜的步骤:

                (1).用二维数组将地图上的障碍等特殊位置标注出来,并开二位数组去记录每个点是否走过。

                (2).用两个一维数组或一个二位数组定义下一步的方向(后面例题会用讲解)  

                (3).从起点开始向下一步走,使用for循环,判断是否越界,是否是障碍物,是否符合条件

                (4).如果符合条件,则将该点标记为已走过,对这个点进行dfs,并做好回溯操作,即将标记取消。(例题中有详解)

                (5).在主函数中,将起点记为已走过(否则会死循环!!!!)

             

                  3.例题详解:

        很正常的一道深搜题目,按照上面的方式分析:

int n,m,t,sx,sy,fx,fy,sum;
bool zh[10][10],use[10][10];

(1).设置二维数组,标记是否是障碍物,是否已经走过。 

int dx[4]={0,0,1,-1};

//下一步x的变化

int dy[4]={-1,1,0,0};

//下一步y的变化

for(int i=0;i<=3;i++){
		int nx,ny;
		nx=x+dx[i];
		ny=y+dy[i];

//nx,ny是下一个点的坐标

(2).设置下一步走的方向,这里用了两个一维数组,分别定义x和y的方向。使用for循环,向上下左右进行前进。 

if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&zh[nx][ny]==0&&use[nx][ny]==0)

(3).判断是否符合要求。 

	    {
			use[nx][ny]=1;
			dfs(nx,ny);
			use[nx][ny]=0;
		}

(4).如果符合要求,就继续深搜,并将标记点消去,以便回溯可以进行。 

int main()
{
	cin>>n>>m>>t;
	cin>>sx>>sy>>fx>>fy;
	for(int i=1;i<=t;i++)
	{
		int x,y;
		cin>>x>>y;
		zh[x][y]=1;
	}
	use[sx][sy]=1;

//将起始点标记为已走过

	dfs(sx,sy);
	cout<<sum;
	return 0;
}

(5)  .在主函数中列出地图,并将起始点标记为已走过。

完 整 代 码:

#include<iostream>
using namespace std;
int n,m,t,sx,sy,fx,fy,sum;
bool zh[10][10],use[10][10];
int dx[4]={0,0,1,-1};
int dy[4]={-1,1,0,0};
void dfs (int x,int y)
{
	if(x==fx&&y==fy)
	{
		sum++;
		return ;
	}
	for(int i=0;i<=3;i++){
		int nx,ny;
		nx=x+dx[i];
		ny=y+dy[i];
		if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&zh[nx][ny]==0&&use[nx][ny]==0)
		{
			use[nx][ny]=1;
			dfs(nx,ny);
			use[nx][ny]=0;
		}
	}
}
int main()
{
	cin>>n>>m>>t;
	cin>>sx>>sy>>fx>>fy;
	for(int i=1;i<=t;i++)
	{
		int x,y;
		cin>>x>>y;
		zh[x][y]=1;
	}
	use[sx][sy]=1;
	dfs(sx,sy);
	cout<<sum;
	return 0;
}

二 .广搜

        1.广搜含义:

         广搜就是多个方向同时前进,直到搜索到所需要的目标。依然类比一场战争,广搜就是同时派出多支部队,同时向不同的方向行进,直到有一支队伍率先找到目标,其他部队停止追击(或者继续前进)。  所以广搜的精髓在于所有方向同时前进,为了实现这个精髓,应当使所有同一阶段的点先移动完成,然后再让他产生的点移动,所以自然想到使用队列,每次弹出首元素,就实现了先进先出。

        2.广搜步骤:

        (1).开数组记录是否走过该点,设置前进的方向,同深搜,如:上下左右.......;并定义结束条件。

        (2).设置能包含所需元素的队列(这个地方会影响后续的复杂程度),并将第一个元素压入队列中。

        (3)当队列非空,取出首元素作为作为下一个移动对象,并在队列中删除首元素(以防多次操作)。.

        (4).使用for循环移动,如果不越界且未走过,则将其压入队列,并标记为走过(同样是防止一个点走多次)。

      .

        3.广搜例题:

 按照以上步骤进行:

(1).开数组记录是否走过该点,设置前进的方向,同深搜,如:上下左右.......;并定义结束条件。

int mp[1005][1005],value[1005][1005];
int m,n,ex,ey,sx,sy;
int nx,ny;
int next_x;
int next_y;

//mp数组记录图上的点
//value函数记录到每一个点所需的最小步数

int movx[8]={1,2,2,1,-1,-2,-2,-1};
int movy[8]={2,1,-1,-2,-2,-1,1,2};

//两个数组,一个表示x轴移动,一个是y轴的移动

memset(mp,0,sizeof(mp));
memset(value,-1,sizeof(value));

//初始化

 (2).设置能包含所需元素的队列(这个地方会影响后续的复杂程度),并将第一个元素压入队列中。

queue <pair<int,int> > p;
mp[x][y]=1;
value[x][y]=0;

//将第一个点初始化

p.push(make_pair(x,y));

//将第一个点压入队列

这里我是用pair与queue结合,直接压入x与y两个值。

pair头函数是utility,关于vector和pair的相关使用可以参考我上一篇文章的万字解析。

(3)当队列非空,取出首元素作为作为下一个移动对象,并在队列中删除首元素(以防多次操作)。.

	while(!p.empty()){
		nx=p.front().first;
		ny=p.front().second;

//取出第一个元素

		p.pop();

//将第一个元素从队列中取出

        (4).使用for循环移动,如果不越界且未走过,则将其压入队列,并标记为走过(同样是防止一个点走多次)。

for(int i=0;i<8;i++){
		next_x=nx+movx[i];
		next_y=ny+movy[i];
			if(next_x>=0&&next_y>=0&&next_y<n&&next_x<m&&mp[next_x][next_y]==0){

//判断条件

		p.push(make_pair(next_x,next_y));
		
//成立就压入队列

		mp[next_x][next_y]=1;
				
//这一点的数值由上一点得来

        value[next_x][next_y]=value[nx][ny]+1;    		
			}
		}

我这道题是相当简单的题,只用判断是否越界,其他情况因题而异

完整代码:

//主函数:
//1.列每一点情况
//2.引用bfs,并输出答案
//
//bfs:
//1.设置走位方向,设置结束标识 
//2.设置queue与pair,存储二维坐标
//3.判断空栈,出栈,移位,判断,入栈 

#include<iostream>
#include<utility>
#include<queue>
#include<string.h>
using namespace std;

int mp[1005][1005],value[1005][1005];
int m,n,ex,ey,sx,sy;
int nx,ny;
int next_x;
int next_y;
void bfs(int x,int y){
	int movx[8]={1,2,2,1,-1,-2,-2,-1};
	int movy[8]={2,1,-1,-2,-2,-1,1,2};
	memset(mp,0,sizeof(mp));
	memset(value,-1,sizeof(value));
	queue <pair<int,int> > p;
	mp[x][y]=1;
	value[x][y]=0;
	p.push(make_pair(x,y));
	while(!p.empty()){
		nx=p.front().first;
		ny=p.front().second;
		p.pop();
		for(int i=0;i<8;i++){
		next_x=nx+movx[i];
		next_y=ny+movy[i];
			if(next_x>=0&&next_y>=0&&next_y<n&&next_x<m&&mp[next_x][next_y]==0){
		p.push(make_pair(next_x,next_y));
				mp[next_x][next_y]=1;
				value[next_x][next_y]=value[nx][ny]+1;    		
			}
		}

	}
} 

int main(){
	cin>>m>>n;
	cin>>sx>>sy;
	bfs(sx-1,sy-1);
	for(int i=0;i<m;i++){
		for(int j=0;j<n-1;j++){
			cout<<value[i][j]<<"  ";
		}
		cout<<value[i][n-1]<<endl;
	}
	return 0;
} 

今天介绍的两道题比较简单,是对深搜,广搜的直接应用。但无论搜索相关的题目有多复杂,本质都是要有如上的两种思考过程,在这个框架基础上完成自己特定目标。

今天的分享就这么多了,有疑问的地方欢迎评论区交流。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱码天天

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

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

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

打赏作者

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

抵扣说明:

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

余额充值