一本通之广度搜索合集

本文回顾并总结了四个使用广度优先搜索(BFS)解决的典型问题:求解连通块(1329细胞)、象棋步数计算(1330最少步数)、仙岛求药路径(1251)、以及迷宫和走迷宫问题(1255和1252)。通过实际代码演示,巩固和复习了搜索算法在实际编程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一本通之广度搜索合集

今天的目的是练习所有关于搜索的题目,我一定加油,新题到今天就结束吧
关于洛谷上的题,也是尽量的能找回来就找回来,一些水题我就不整理了
废话少说,开干吧
其实搜索对于我来说并不难,之前在日照也都训练过了,但是有些遗忘,所以还得重复学习一下

1329 细胞

细胞,貌似听说过这个题
也就是求连通块吧,不就是油田吗?
貌似这个题连数据范围都没有
注意这里要单独开一个字符输入,因为数组都是连一块的
还有就是,我在这里开了一个二维数组来存队列,其实意思和queue是一样的只不过要开结构体,这样更方便

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
int n,m;
char c;
int a[105][105];
int dx[]={1,-1,0,0};
int dy[]={0,0,-1,1};//方位数组 
int ans;
void bfs(int x,int y)
{
	ans++;
	int head=0,tail=1;//初始化队列的头和尾
	int que[10000][2];//也可以用stl的就结构体队列实现
	a[x][y]=0; 
	que[1][0]=x,que[1][1]=y;//进入队列,从当前元素开始
	int xx,yy;
	while(head<tail)
	{
		head++;
		for(int i=0;i<=3;i++)
		{
			xx=que[head][0]+dx[i];
			yy=que[head][1]+dy[i];
			if(a[xx][yy])
			{
				tail++;
				que[tail][0]=xx;
				que[tail][1]=yy;
				a[xx][yy]=0;
			}
			//标记已经搜索过了,也就是 将所有连通的点都进行标记 
		}
	 } 
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>c;
			a[i][j]=c-'0';//注意这里要单独开一个字符输入,因为数组都是连一块的
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j])
				bfs(i,j);
		}
	}
	cout<<ans<<endl;
	return 0;
 } 

1330 最少步数

象棋的步数其实都差不多的套路,只不过这个题的方位数组需要开的大一点

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
int n,m; 
int dx[13]={0,-2,-2,-2,-2,-1,-1,1, 1,2,2, 2, 2}; 
int dy[13]={0, 2, 1,-1,-2, 2,-2,2,-2,2,1,-1,-2};//方位数组 
int x2,y2,x3,y3;
int book[101][101];
int que[10000][4];//队列,前两个存储坐标,第三个存储步数 
int main()
{
	cin>>x2>>y2;
	cin>>x3>>y3;
	memset(book,-1,sizeof(book));
	book[1][1]=1;
	que[1][1]=1;
	que[1][2]=1;
	que[1][3]=0;
	int head=1,tail=1;
	int xx,yy;
	while(head<=tail)
	{
		for(int i=1;i<=12;i++)
		{
			xx=que[head][1]+dx[i];
			yy=que[head][2]+dy[i];
			if(xx>0&&yy>0)//判断出界
			{
				if(book[xx][yy]==-1)//为访问并且不出界就更新 
				{
					book[xx][yy]=que[head][3]+1;//这个点为head转移过来的,所以加一
					tail++;
					que[tail][1]=xx;
					que[tail][2]=yy;
					que[tail][3]=book[xx][yy];//直接计算步数
					if(book[x2][y2]>0&&book[x3][y3]>0)
					{
						cout<<book[x2][y2]<<endl;
						cout<<book[x3][y3]<<endl;
						return 0;
					 } 
				}
			 } 
		}
		head++;
	 } 
}

卡了我好长时间

1251 仙岛求药

好早就听说过这个题,听说zp老师之前做到晚上12点还没做出来…
今天是我听说之后的一年后,正式直面他
但是这个题貌似并不难啊
然后这个题我先用广搜做一遍啊

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
struct node{
    int h,z,step;
}cur,net;
queue<node>s;
char a;
int map[30][30];
bool vis[30][30];
int d[5]={1,0,-1,0,1};
int n,m;
int sx,sy,ex,ey;
void bfs()
{
    if(sx==ex&&sy==ey)
    {
        printf("0\n");return ;
    }
    while(!s.empty())s.pop();
    cur.h=sx;
    cur.z=sy;
    cur.step=0;
    s.push(cur);
    vis[cur.h][cur.z]=1;
    while(!s.empty() )
    {
        cur=s.front() ;
        s.pop() ;
        for(int i=0;i<4;++i)
        {
            int xx=cur.h +d[i];
            int yy=cur.z +d[i+1];
            if(xx>0&&yy>0&&xx<=n&&yy<=m&&map[xx][yy]!=1&&!vis[xx][yy])
            {
                if(xx==ex&&yy==ey)
                {
                    printf("%d\n",cur.step+1);
                    return ;
                }
                net.h=xx;
                net.z=yy;
                net.step=cur.step+1;
                vis[xx][yy]=1;
                s.push(net);
            }
        }
    }
    printf("-1\n");
}
int main()
{
    scanf("%d%d",&n,&m);
    while(n!=0&&m!=0)
    {
        memset(vis,0,sizeof(vis));
        memset(map,0,sizeof(map));
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
            {
                cin>>a;
                if(a=='@'){sx=i;sy=j;}
                else if(a=='*'){ex=i;ey=j;}
                else if(a=='#'){map[i][j]=1;}
            }
        bfs();
        scanf("%d%d",&n,&m);
    }
    return 0;
}

1253 抓住那只牛

之前在open上做过,所以这里就直接把代码拿过来了
其实这种做法比较简单

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
int tme[100050];
queue<int> q;
int n,m;
void inp(int i,int j){
	if(j>=0&&j<=100000&&tme[j]==-1)
	{
		tme[j]=tme[i]+1;//计算路径
		q.push(j);//进入队列
	}
}
int main(){
	memset(tme,-1,sizeof(tme));
	cin>>n>>m;
	tme[n]=0;
	q.push(n);
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		if(x==m)
		{
			cout<<tme[x]<<endl;
			return 0;
		}	
		inp(x,x+1);
		inp(x,x-1);
		inp(x,2*x);	//三个牛的方向进行搜索
	}
	return 0; 
}

1255 迷宫问题

还有三个题,广搜就结束了
这个题貌似很简单

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 26
using namespace std;
int n=5;
char a[N][N];
bool vis[N][N];
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
struct node
{
    int x;
    int y;
}q[N*100],res[N][N];
void print(int x,int y)
{
    if(x==-1&&y==-1)
        return;
    print(res[x][y].x,res[x][y].y);//递归输出路径 
    printf("(%d, %d)\n",x,y);//中文的逗号。。。 
}
void bfs(int sx,int sy,int ex,int ey)
{
    int head=1,tail=1;
    memset(vis,0,sizeof(vis));
 
    vis[sx][sy]=1;
    res[sx][sy].x=-1;
    res[sx][sy].y=-1;
    q[tail].x=sx;
    q[tail].y=sy;//存储队列 
    tail++;
 
    while(head<tail)
    {
        int x=q[head].x;
        int y=q[head].y;
        if(x==ex&&y==ey)
        {
            print(x,y);
            break;
        }
        for(int i=0;i<4;i++)
        {
            int nx=x+dir[i][0];
            int ny=y+dir[i][1];
            if(nx>=0&&nx<n&&ny>=0&&ny<n&&vis[nx][ny]==0&&a[nx][ny]==0)
            {
                vis[nx][ny]=1;
                q[tail].x=nx;
                q[tail].y=ny;
                tail++;
                res[nx][ny].x=x;
                res[nx][ny].y=y;
            }
        }
        head++;
    }
}
int main()
{
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            scanf("%d",&a[i][j]);
    bfs(0,0,n-1,n-1);//起点,终点 
 
    return 0;
}

1252 走迷宫

我不得不说这几个题的标题都如此的草率
其实这几个题都差不多性质,我也懒得做了

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N = 10010;
int r,c;
char map[N][N];
bool vis[N][N]={0};
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
struct node
{
	int x;
	int y;
	int step;//记录步数 
}q[N];
void bfs(int sx,int sy,int ex,int ey)
{
	int head=1,tail=1;
	vis[sx][sy]=1;
	q[tail].x=sx;
	q[tail].y=sy;
	q[tail].step=1;//初始进队 
	tail++;
	while(head<tail)
	{
		int x=q[head].x;
		int y=q[head].y;
		int step=q[head].step;//从队首开始 
		if(x==ex&&y==ey)
		{
			printf("%d\n",step);
			break;
		}
		for(int i=0;i<4;i++)
		{
			int nx = x + dir[i][0];
			int ny = y + dir[i][1];//获取方向 
			if(nx>=0&&nx<r&&ny>=0&&ny<c&&!vis[nx][ny]&&map[nx][ny]=='.')
			{//判断是否出界 
				vis[nx][ny]=1;
				q[tail].x=nx;
				q[tail].y=ny;
				q[tail].step=step+1;
				tail++;
			}
		}
		head++;
	}
}

int main()
{
	scanf("%d%d",&r,&c);
	for(int i=0;i<r;i++)
	  scanf("%s",map[i]);
	  bfs(0,0,r-1,c-1); //起点终点 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值