一本通之广度搜索合集

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

一本通之广度搜索合集

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

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;
}

<think>好的,我需要处理用户关于“一本1385”相关的IT内容或编程题解的查询。首先,我得确认用户提到的“一本1385”具体指的是哪本书或哪个资源中的题目。根据提供的引用内容,用户引用了信息学奥赛一本的多道题目,比如1324、1329等,这些可能来自同一本书的不同章节。 接下来,我需要查看用户提供的引用内容,看看是否有直接提到1385的相关信息。检查引用[1]到[4],发现它们分别涉及装箱问题、最大数位置、整数区间和细胞问题,但没有提到1385。因此,用户的问题可能不在现有的引用资料中,或者需要进一步推断。 由于用户提供的引用中没有直接关于1385的内容,我需要考虑是否可能过其他线索来推测。例如,信息学奥赛一本的题目常按章节和编号排列,1385可能属于某个特定章节,比如动态规划、图论或搜索算法等。需要进一步分析可能的题目类型。 另外,用户可能需要1385的题解或相关的编程思路。由于没有具体题目描述,可能需要建议用户提供更多信息,或者根据常见的信息学奥赛题型给出一般性的建议。例如,1385可能涉及广度优先搜索、动态规划或贪心算法,这些在之前的引用中出现过。 同时,用户可能希望得到类似引用中提到的题解结构,包括解题思路和代码示例。因此,即使没有具体的1385内容,也可以推荐用的解题方法,并引导用户参考类似的题目,如1329广度优先搜索方法或1324的贪心算法应用。 最后,考虑到用户可能需要生成相关问题,我可以围绕信息学奥赛常见的题型和算法,提出几个可能相关的问题,帮助用户进一步探索。例如,动态规划的应用、图论问题或高级搜索技巧等。</think>根据您提供的信息,"一本1385"暂时未在现有引用资料中找到直接对应的题解或内容。以下提供几种可能性及建议: ### 可能涉及的内容推测 1. **动态规划类题目** 《信息学奥赛一本》中13XX系列常涉及动态规划,例如: - 最长公共子序列$LCS$ - 背包问题变种 - 区间DP(参考1324的区间处理技巧[^3]) 2. **图论问题** 1385可能与图的遍历、最短路径相关,建议结合: - 广度优先搜索(参考1329细胞问题的BFS实现[^4]) - Dijkstra算法或Floyd算法 3. **高级数据结构** 可能涉及树状数组、线段树等应用 ### 建议解决方案 1. **题目特征确认** 请提供题目具体描述或输入输出样例,例如: - 是否涉及矩阵操作? - 是否存在特殊约束条件? - 是否需要时间复杂度优化? 2. **用解题模板** ```python # 动态规划用框架示例 def dp_solution(inputs): n = len(inputs) dp = [[0]*n for _ in range(n)] for i in range(n): for j in range(i+1, n): dp[i][j] = max(dp[i][j-1], inputs[j] + dp[i][j-2]) return dp[0][n-1] ``` 3. **参考类似题型** - 装箱问题的空间优化思路(引用[1]的JAVA实现) - 细胞问题的BFS队列管理方法(引用[4]的坐标记录技巧)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值