了解什么是BFS

这篇博客介绍了深度优先搜索(DFS)和广度优先搜索(BFS)的基本概念和区别。DFS通过递归实现,沿着一条路径深入搜索直至找到目标或无法继续;BFS则采用队列,逐层遍历。文中通过面积计算问题分别展示了DFS和BFS的解决方案,并指出BFS适用于解决权值相同的最短路径问题。此外,还提供了BFS解决救援行动问题的实例,展示其寻找最短时间路径的能力。
摘要由CSDN通过智能技术生成

第十三讲 BFS

DFS复习

DFS深度优先搜索,是将问题抽象成一种树结构,带着目的性的进行搜索,一路走到底,直到达到目标。深度优先搜索借助递归来实现,递归下去,回溯上来,如果没有走到底就发现下面的元素都无法满足题目要求时,则停止对该路的搜索。

DFS遍历步骤(图示)
  1. 从根节点1开始搜索

在这里插入图片描述

  1. 找出与此点邻接的且尚未遍历的点

  2. 遍历完所有节点后,将栈中元素弹出,DFS完成

例题

面积计算(深搜)

分析:因为是要求闭合*围成的曲线,第一步把四周的0,以及该0的四周的0变成*号,之后再枚举0的个数即可。

#include<iostream>
#include<cstring>
using namespace std;
char a[55][55];
int dx[]={0,-1,1,0},dy[]={1,0,0,-1};//搜索上下左右,可以少写几个if 
int len=0;
void dfs(int x,int y){//参数为 为'0' 点的横纵坐标 
	a[x][y]='*';
	for(int i=0;i<4;i++){
		if(a[x+dx[i]][y+dy[i]]=='0')
			dfs(x+dx[i],y+dy[i]);
	}
	return;
}
int main(){
	cin>>a[0];
	int m=1;
	int len=strlen(a[0]);
	while(cin>>a[m]) ++m;
	for(int i=0;i<m;i++){//从边界开始搜索,将外围的染黑 
		if(a[i][0]=='0')
			dfs(i,0);
		if(a[i][len-1]=='0')
			dfs(i,len-1);
	}
	for(int i=0;i<len;i++){
		if(a[0][i]=='0')
			dfs(0,i);
		if(a[m-1][i]=='0')
			dfs(m-1,i);
	}
	int sum=0;
	for(int i=0;i<m;i++)
		for(int j=0;j<len;j++)
			if(a[i][j]=='0')
				sum++;
	cout<<sum;
}

BFS

BFS与DFS的区别与联系

BFS和DFS都属于优先搜索算法,BFS又称宽度优先搜索,它们的主要区别在于搜索方式不同,DFS是一个劲往下搜索并带有目的性的搜索,当不满足条件时就回溯,而BFS是一层一层的遍历。

数据结构空间复杂度可以解决的问题
DFSO(h)具体问题具体分析
BFS队列O(2^n)权值相同的最短路问题

如果按照BFS遍历该图中的元素,遍历顺序为 1->2->8->3->5->6->9->4->7

BFS模板

广度优先搜索算法的基本思想:
1、对于初始状态入队,设置初始状态为已访问
2、如果队列不为空时,出队队头元素,否则跳到第5步
3、检查出队的元素是否为最终解,如果是则跳到第5步。
4、对于出队的元素,检查所有相邻状态,如果有效并且未访问,则将
所有有效的相邻状态进行入队,并且设置这些状态为已访问,然后
跳到第2步重复执行
5、检查最后出队的元素是否为最终解,如果是输出结果,否则说明无解

void bfs(){
	queue<int>q;
	st[1]=1;//说明第一个点已经遍历过了 
	q.push(1);//把第一个变量入队
	while(q.size()) {
		int t=q.front();//取出队头元素 
		q.pop();
		for(根据实际问题分析,遍历跟这个点相关的点){
		if(满足题目的条件){
			q.push(将该点入队);
		} 
	}
}
为什么BFS能解决最短路问题?

如果要求图中 点1 和点4之间的最短路径,用BFS是十分好求的,为什么很容易,因为BFS是一层一层的遍历,它先遍历离顶点距离为1 的点,再遍历与顶点距离为2的点……

但是BFS只能解决权值相同的最短路问题,如果想要解决其他类型的最短路问题,需要用到其他的算法,以后在图论章节中会学到。

救援行动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HVbfSHBP-1639307459303)(C:\Users\ZZWGY\AppData\Roaming\Typora\typora-user-images\image-20211209092730639.png)]

这道题求最短时间,并且移动一步所需要的时间是相同的

#include <iostream>
#include <cstdio>
#include <queue>
#include<cstring>
using namespace std;
int n,m,flag=0;
int dx[]={1,0,0,-1},dy[]={0,-1,1,0};
int vis[205][205];
string w[205];
bool valid(int x,int y){
	return x>=0&&x<n&&y>=0&&y<m;
}
struct man
{
    int x,y,step;
};
queue<man>q;
void bfs(man s)
{
    q.push(s);//将营救队员初始位置入队 
    while(!q.empty())//队列非空 
    {
        man t=q.front();
        //printf("%d %d %d\n",t.x,t.y,t.step);
        if(w[t.x][t.y]=='a'){printf("%d\n",t.step);flag=1;return;}//如果走到'a'点,就结束 
        else if(w[t.x][t.y]=='x'){t.step++;q.pop();q.push(t);w[t.x][t.y]='.';continue;}//遇到怪兽就把时间+1,再重新入队 
        q.pop();
        for(int i=0;i<4;i++)//上下左右搜索 
        {
            int xx=t.x+dx[i];int yy=t.y+dy[i];
            if(valid(xx,yy)&&vis[xx][yy]==0&&w[xx][yy]!='#')
            {
                man k;
                vis[xx][yy]=1;
                k.step=t.step+1;k.x=xx;k.y=yy;q.push(k);
            }
        }
    }
}
int main()
{
    memset(vis,0,sizeof(vis));
    scanf("%d%d",&n,&m);
	man s;
    for(int i=0;i<n;i++)cin>>w[i];//输入地图 
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
        {
            if(w[i][j]=='r')//初始化营救队员所站的位置 
            {
 
                s.x=i;
                s.y=j;
                s.step=0;
            }
        }
    bfs(s);
    if(flag==0)printf("NO ANSWER\n");
    return 0;
}

面积计算(宽搜)

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
char a[1500][250];
int dx[]={0,0,-1,1},dy[]={-1,1,0,0},len,k;//用dx,dy数组记录上下左右搜索坐标的变化情况 
bool valid(int x,int y){//判断新坐标是否越界 
	return x>=1&&x<k&&y>=1&&y<=len;
}
void bfs(int x,int y){
	a[x][y]='1';//将为0的点变为1 
	PII t=make_pair(x,y);//看不懂这个语句的,自行搜索STL 中的pair模板 
	queue<PII> q;
	q.push(t);// 将该点坐标放进队头
	while(q.size()){
		PII t=q.front();//队头出队 
		q.pop();
		for(int i=0;i<4;i++){//向它的四周搜素 
			int x1=t.first+dx[i];
			int y1=t.second+dy[i];
			if(valid(x1,y1)&&a[x1][y1]=='0'){//将新的符合条件的点入队 
				a[x1][y1]='1';
				PII t=make_pair(x1,y1);
				q.push(t);
			}
		}
	}
}
int main(){
	k=1;
	cin>>(a[k++]+1);
	while(cin>>(a[k]+1)){
		k++;
	}
	len=strlen(a[1]+1);
	for(int i=1;i<k;i++){
		if(a[i][1]=='0'){
			bfs(i,1);
		}
		if(a[i][len]=='0'){
			bfs(i,len);
		}
		
	}
	for(int i=1;i<=len;i++){
		if(a[1][i]=='0')
			bfs(1,i);//如果边界点为0,就向它上下左右四个方向搜索 
		if(a[k-1][i]=='0')
			bfs(k-1,i);
	}
	int sum=0;
	for(int i=1;i<k;i++)
		for(int j=1;j<=len;j++)
			if(a[i][j]=='0')
				sum++;
	cout<<sum<<endl;
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值