我对广度优先搜索(BFS)的理解
广度优先搜索(BFS)是一种常见的图和树的遍历算法,其基本思想是按照深度从浅到深的顺序访问图或树中的节点。它从根节点开始(也可以是其他指定的节点),然后探索所有相邻的节点,然后再探索这些节点的相邻节点,以此类推。BFS使用队列数据结构来存储待访问的节点,遵循“先入先出”的原则。BFS常用于迷宫问题,最短路径等问题的求解。
学习广搜的艰难历程
与dfs不同的是bfs需要用队列来存储节点,一开始看的很多讲解视频和帖子都是用的C++直接请求一个队列(C好像是不能这么玩的,C++我又不会,当时也不会用C写队列),虽然基本都有解释队列的使用过程,但是都没有给出队列的源代码,以至于我一直不知道如何在C中实现队列。最后我还是决定专门去学习一下队列在C语言中的实现。我首先是在《啊哈算法》这本书中了解到了最简单的C语言队列的实现,原码如下:
这样写简单易懂,但是会对空间有很大的浪费,这显然不是我想要的版本。然后是在小破站了解到了循环队列,结合《啊哈算法》中的队列实现这才得以完成BFS后面的学习。
洛谷【马的遍历】题解
刚搞懂bfs我就迫不及待的写了这一题
原题点这里-->P1443 马的遍历 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
有一个 n×m 的棋盘,在某个点 (x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。
输入格式
输入只有一行四个整数,分别为 n,m,x,y。
输出格式
一个 n×m 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 −1−1)。
输入输出样例
输入 #1
3 3 1 1
输出 #1
0 3 2 3 -1 1 2 1 4
数据规模与约定
对于全部的测试点,保证 1≤x≤n≤400,1≤y≤m≤400。
源代码
想说的话都在注释里了
#include<stdio.h>
#define MAX_SIZE 10000//这里决定了队列的大小,开小了队列可能会爆掉导致出错
typedef struct{
int data[MAX_SIZE][2];//开二维数组因为要存横纵坐标
int front;
int rear;
}CircularQueue;//这是我们要用的队列
int dx[8]={2,2,1,-1,-2,-2,-1,1};
int dy[8]={-1,1,2,2,1,-1,-2,-2};//分别对应马的八个走向
int n,m,a[402][402],p,q;//数组a用来记录走到该点的步数,p,q分别为起始点的横纵坐标
int main()
{
scanf("%d%d%d%d",&n,&m,&p,&q);
CircularQueue queue;
queue.front=queue.rear=0;//定义一个队列并初始化
queue.data[queue.rear][0]=p;
queue.data[queue.rear][1]=q;
queue.rear=(queue.rear+1)%MAX_SIZE;//将起始点入队
while(queue.front!=queue.rear)//当队空时结束
{
for(int i=0;i<8;i++)//试探马下一步可能走到的八个位置
{
int x=queue.data[queue.front][0]+dx[i];
int y=queue.data[queue.front][1]+dy[i];
if(x>0&&x<=n&&y>0&&y<=m&&(x!=p||y!=q)&&a[x][y]==0)//入队的条件
{
a[x][y]=a[queue.data[queue.front][0]] [queue.data[queue.front][1]]+1;//标记走到该点所花的步数
queue.data[queue.rear][0]=x;
queue.data[queue.rear][1]=y;
queue.rear=(queue.rear+1)%MAX_SIZE;//入队
}
}
queue.front=(queue.front+1)%MAX_SIZE;//队首出队
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)//双重for循环遍历棋盘用于输出结果
{
if(a[i][j]==0)//值为零时可能是起始点也可能是到达不了,所以要再判断一下
{
if(i==p&&j==q)
printf("0 ");
else
printf("-1 ");
}
else
printf("%d ",a[i][j]);
}
printf("\n");
}
return 0;
}
小结
广度优先搜索在使用队列时要特别注意入队的条件,还有对已到达位置的标记。
发现撒子问题记得提醒我呦