算法练习题7---BFS与DFS练习


# 前言

BFS,DFS是数据结构与算法系列课程中非常重要,也是非常经典的两个算法。这一次,我想通过一道例题进行一次系统的总结,首先能够充分的理解BFS,DFS两个算法,然后可以掌握BFS,DFS两种算法思想,运用更加复杂,更加晦涩的算法题目中。

一、题目描述

题目“Red and Black”

有一个长方形的房间,铺着方形瓷砖,瓷砖为红色或黑色。一个人站在黑色砖上。他可以按上,下、左、右方向移动到相邻的瓷砖。但他不能在红色瓷砖上移动,只能在黑色瓷砖上移动。编程计算他可以到达的黑色瓷砖的数量。

输入:第1行包含两个正整数 W 和 H . W 和 H 分别表示x方向和 y 方向上的瓷砖数量。 W 和 H 均不超过20。下面有 H 行,每行包含 W 个字符。每个字符表示一片瓷砖的颜色。用符号表示如下:“.” 表示黑色瓷砖;“#” 表示红色瓷砖;“@” 代表黑色瓷砖上的人,在数据集中只出现一次。

输出:一个数字,这个人从初始瓷砖能到达的黑色瓷砖总数量(包括起点)。

样例输入:

6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
...@...
###.###
..#.#..
..#.#..
0 0

样例输出:

45
59
6
13

二、BFS

BFS又称广度优先算法,所谓广度优先,是利用队列先进先出的特性,将每一个点可以到达的所有点都加入到队列中,然后移除该点,再遍历队列的首个元素,重复次操作。一般的题目中,都用二维数组来表示一个矩阵,一般可以移动的方向为上、下、左、右,那么需要对每一个队列中的点依次进行上、下、左、右这几个方向的查找,把符合要求的点放入队列中(该点一定是未被遍历过的)。直到队列中为空。

三、DFS

DFS又称深度优先算法,所谓深度优先,是利用递归思想的特性,一直朝着一个方向遍历,直到没有办法前进为止,这个时候,当遇到无路可走时,就要进行回溯。那么如何实现回溯呢,这个其实我们不需要去考虑内部的实现过程,因为递归的回溯是依靠栈去实现,我们只需要记住递归函数的返回位置是它在所的函数中的位置的下一条语句。掌握好递归的这个特性,我们就可以去巧妙的设计递归程序,来解决该问题。

另一问题就是,如何在递归函数中进行其他方向的遍历?在该题目中,递归程序可以嵌套在for循环中,用for循环保证4个方向的执行,而递归算法本身又能保证优先朝着一个固定的方向一直遍历下去,那么二者结合也就构成了最终的DFS算法。

四、程序代码----BFS算法

#include<bits/stdc++.h>
using namespace std;
char room[23][23];  //记录已经遍历过的节点,防止重复 
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};  //依次为向左,向上,向右,向下 
int Wx,Hy,num; 
#define CHECK(x,y)(x<Wx&&x>=0&&y>=0&&y<Hy)
struct node
{
int x;
int y;
};

void BFS(int dx,int dy)
{
	queue<node> q;  //声明一个队列q,BFS算法的核心 
	num=1;
	node start,next;  //开始节点和下一个节点
	start.x=dx;
	start.y=dy;
	q.push(start);
	while(!q.empty())
	{
		start=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			next.x=start.x+dir[i][0];
			next.y=start.y+dir[i][1];
			if(CHECK(next.x,next.y)&&room[next.x][next.y]=='.')
			{
				room[next.x][next.y]='#'; //进队之后标记被处理 
				num++;
				q.push(next); 
			}
		}
	}
} 
int main()
{
	int x,y,dx,dy;
	while(cin>>Wx>>Hy)
	{
		if(Wx==0&&Hy==0)  //遇到0,0结束 
		{
			break;
		}
		for(y=0;y<Hy;y++)
		{
			for(x=0;x<Wx;x++)
			{
				cin>>room[x][y];
				if(room[x][y]=='@')
				{
					dx=x;
					dy=y;
				}
			}
		}
		num=0;
		BFS(dx,dy);
		cout<<num<<endl;
	}
	return 0;
} 

五、程序代码----DFS算法

#include<bits/stdc++.h>
using namespace std;
char room[23][23];  //记录已经遍历过的节点,防止重复 
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};  //依次为向左,向上,向右,向下 
int Wx,Hy,num; 
#define CHECK(x,y)(x<Wx&&x>=0&&y>=0&&y<Hy)
struct node
{
int x;
int y;
};

void DFS(int dx,int dy)
{
	num++;
	room[dx][dy]='#'; //初次遍历,及时标记
	for(int i=0;i<4;i++)
	{
		int newx=dx+dir[i][0];
		int newy=dy+dir[i][1];
		if(CHECK(newx,newy)&&room[newx][newy]=='.')
		{
			DFS(newx,newy); 
		}
	}
	return;
}
int main()
{
	int x,y,dx,dy;
	while(cin>>Wx>>Hy)
	{
		if(Wx==0&&Hy==0)  //遇到0,0结束 
		{
			break;
		}
		for(y=0;y<Hy;y++)
		{
			for(x=0;x<Wx;x++)
			{
				cin>>room[x][y];
				if(room[x][y]=='@')
				{
					dx=x;
					dy=y;
				}
			}
		}
		num=0;
		DFS(dx,dy); 
		cout<<num<<endl;
	}
	return 0;
} 
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨大熊的代码世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值