广度优先搜索

广度优先搜索算法(又称宽度优先搜索)

         是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

下面我们还是通过一个例子来分析:

有一天,小哈一个人去玩迷宫,但方向感不太好的他很快就迷路了。迷宫由n行m列的单元格组成,每个单元格要么是空地,要么是障碍物。你的任务就是帮助小哈找到一条从迷宫的起点通往小哈所在位置的最短路径。

首先我们可以用一个二维数组来存储这个迷宫,刚开始的时候,小哈处于迷宫的入口处(1,1),小哈在(p,q)。其实就是找从(1,1)到(p,q)的最短路径。广搜就是通过“一层一层”扩展的方法来找到小哈。扩展时每发现一个点就将这个点加入到队列中,直至走到小哈的位置(p,q)是位置。这个扩展的过程可以用一个队列来模拟,这里我们用一个结构体来实现队列。

struct note
{
	int x;//横坐标 
	int y;//纵坐标 
	int s;//步数 
};
struct note que[2501];
int head,tail;
int a[51][51] = {0};//用来存储地图 
int book[51][51] = {0};//数组book的作用是记录哪些点已经在队列中了。
					//防止一个点被重复扩展,并全部初始化为0. 
//最开始的时候需要进行队列初始化,即将队列设置为空。 
head = 1;
tail = 1;
//第一步将(1,1)加入队列,并标记(1,1)已经走过。 
que[tail].x = 1;
que[tail].y = 1;
que[tail].s = 0;
tail ++;
book[1][1] = 1;

然后从(1,1)开始,先尝试往右走到达了(1,2)。

tx = que[head].x;
ty = que[head].y+1; 

需要判断(1,2)是否越界。

if(tx < 1 || tx > n || ty < 1 || ty > m)
	continue;

再判断(1,2)是否为障碍物或者已经在路径中。

if(a[tx][ty] == 0 &&book[tx][ty] == 0)
{

}

如果满足上面的条件,则将(1,2)入队,并标记该点已经走过。

//把这个点标记已经走过
book[tx][ty] = 1;
//注意广搜每个点通常情况下只入队一次,和深搜不同,不需要将book数组还原
//插入新的点到队列中
que[tail].x = tx;
que[tail].y = ty;
que[tail].s = que[head].s + 1;
tail ++;

接下来还要继续尝试往其他方向走。我们发现从(1,1)还可以到达(2,1),因此也需要将(2,1)也加入队列,代码实现和刚才对(1,2)的操作时一样的。

对(1,1)扩展完毕后,其实(1,1)现在对我们来说已经没有用了,此时我们将(1,1)出队。出队的操作就简单的一句话

head ++;

接下来我们需要在刚才新扩展出来的(1,2)和(2,1)两个点的基础上继续向下探索。直至走到小哈的位置,算法结束。为了方便向四个方向扩展,这里需要一个next数组。

int next[4][2] = { {0,1},//向右走 
		{1,0},//向下走 
		{0,-1},//向左走 
		{-1,0} };//向上走 

完整代码

#include<stdio.h>
struct note
{
	int x;
	int y;
	int s;
};
int main()
{
	struct note que[2501];
	int a[51][51] = {0},book[51][51] = {0};
	int next[4][2] = { {0,1},
					{1,0},
					{0,-1},
					{-1,0} };
	int head,tail;
	int i,j,k,n,m,startx,starty,p,q,tx,ty,flag;
	scanf("%d%d",&n,&m);
	for(i = 1; i <= n; i ++)
		for(j = 1; j <= m; j ++)
			scanf("%d",&a[i][j]);
	scanf("%d%d%d%d",&startx,&starty,&p,&q);
	head = 1;
	tail = 1;
	que[tail].x = startx;
	que[tail].y = starty;
	que[tail].s = 0;
	tail ++;
	book[startx][starty] = 1;
	flag = 0;//用来标记是否到达目标点
	//当队列不为空的时候循环 
	while(head < tail)
	{
		for(k = 0; k < 4; k ++)
		{
			tx = que[head].x + next[k][0];
			ty = que[head].y + next[k][1];
			if(tx < 1 || tx > n || ty < 1 || ty > m)
				continue;
			if(a[tx][ty] == 0 && book[tx][ty] == 0)
			{
				book[tx][ty] = 1;
				que[tail].x = tx;
				que[tail].y = ty;
				que[tail].s = que[head].s + 1;
				tail ++;
			}
			if(tx == p &&ty == q)
			{
				flag = 1;
				break;
			}
		}
		if(flag == 1)
			break;
		head ++;
	}
	printf("%d\n",que[tail-1].s);
	return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值