深度优先搜索(DFS)广度优先搜索(BFS)是基本的暴力技术,常用于解决图、树的遍历问题。

  首先考虑算法思路。以老鼠走迷宫为例:

  (1):一只老鼠走迷宫。它在每个路口都选择先走右边,直到碰壁无法继续前进,然后回退一步,这一次走左边,接着继续往下走。用这个办法能走遍所有的路,而且不会重复。这个思路就是DFS。

  (2):一群老鼠走迷宫。假设老鼠是无限多的,这群老鼠进去后,在每个路口派出部分老鼠探索没有走过的路。走某条路的老鼠,如果碰壁无法前进,就停下;如果到达的路口已经有其他的老鼠探索过了,也停下。很显然,所有的道路都会走到,而且不会重复。这个思路就是BFS。

  

  A - Red and Black 

There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he can move only on black tiles.

Write a program to count the number of black tiles which he can reach by repeating the moves described above.

InputThe input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.

There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.

'.' - a black tile
'#' - a red tile
'@' - a man on a black tile(appears exactly once in a data set)
OutputFor each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).
Sample Input

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

Sample Output

45
59
6
13
  题目大意:“#”相当于不能走的陷阱或墙壁,“.”是可以走的路。从@点出发,统计所能到达的地点总数

 代码一:这是初学并查集时硬着头皮用并查集的算法解决了BFS的问题
 #include<iostream>
using namespace std; const int h = ;
char map[h][h];
int key[h*h];
int rrank[h*h];
int n,m,dx,dy; int find(int a){
return a==key[a]? a : key[a]=find(key[a]);
} void key_union(int a,int c){
int fa = find(a);
int fc = find(c);
if(rrank[fa]>rrank[fc])
key[fc] = fa;
else{
key[fa] = fc;
if(rrank[fa]==rrank[fc])
rrank[fc]++;
}
} int num(int a){
int k = find(a);
int ans = ;
for(int i=;i<=m;i++)
for(int j=;j<=n;j++)
if(find(i*n+j)==k)
ans++; return ans;
} int main()
{
while(scanf("%d %d",&n,&m)!=EOF){
if(n==&&m==) break;
for(int i=;i<=m;i++){
cin.get();
for(int j=;j<=n;j++){
scanf("%c",&map[i][j]);
if(map[i][j]!='#') key[i*n+j] = i*n+j;
else key[i*n+j] = ;
if(map[i][j]=='@'){//找到@的坐标
dx = i;
dy = j;
map[i][j] = '.';
}
}
} for(int i=;i<m;i++){
for(int j=;j<n;j++){
if(key[i*n+j]){
if(key[i*n+j+])
key_union(i*n+j,i*n+j+);
if(key[i*n+n+j])
key_union(i*n+n+j,i*n+j);
}
}
if(key[i*n+n])
if(key[i*n+*n])
key_union(i*n+*n,i*n+n);
}
for(int i=;i<n;i++)
if(key[m*n+i])
if(key[m*n+i+])
key_union(m*n+i,m*n+i+); int ans = num(dx*n+dy);
printf("%d\n",ans);
}
}

  代码二:这是还分不清DFS和BFS时写的DFS算法(比后面的BFS要简洁很多,不知道为什么作为BFS的例题放在这里)

 #include<iostream>
using namespace std; int mov[][] = {-,,,,,-,,};
int sum,w,h;
char s[][]; void dfs(int x,int y){
sum++;//计数
s[x][y] = '#';
for(int i=;i<;++i){//四个方向前进
int tx = x+mov[i][];
int ty = y+mov[i][]; if(s[tx][ty]=='.' && tx>= && tx<h && ty>= && ty<w)
dfs(tx,ty);//判断该点可行后进入dfs
}
} int main()
{
int x,y;
while(scanf("%d %d",&w,&h)!=EOF){
if(w==&&h==) break;
for(int i=;i<h;i++){
cin.get();
for(int j=;j<w;j++){
scanf("%c",&s[i][j]);
if(s[i][j]=='@'){//起点
x = i;
y = j;
}
}
}
sum = ;
dfs(x,y);
printf("%d\n",sum);
}
return ;
}

  代码三:引自《算法竞赛入门到进阶》中的解题代码 BFS算法

 #include<bits/stdc++.h>
using namespace std; char room[][];
int dir[][] = { //左上角的坐标是(0,0)
{-, }, //向左
{, -}, //向上
{, }, //向右
{, -} //向下
}; int Wx, Hy, num;
#define check(x, y)(x<Wx && x>=0 && y>=0 && y<Hy) //是否在room中
struct node{int x, y}; void BFS(int dx, int dy){
num = ;
queue<node> q;
node start, next;
start.x = dx;
start.y = dy;
q.push(start);//插入队列 while(!q.empty()){//直到队列为空
start = q.front();//取队首元素,即此轮循环的出发点
q.pop();//删除队首元素(以取出) for(int i=; i<; i++){//往左上右下四个方向逐一搜索
next.x = start.x + dir[i][];
next.y = start.y + dir[i][];
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(~scanf("%d %d",&Wx, &Hy)){
if(Wx== && Hy==)
break;
for(y=; y<Hy; y++){
for(x=; x<Wx; x++){
scanf("%d",&room[x][y]);
if(room[x][y] == '@'){//找到起点坐标
dx = x;
dy = y;
}
}
}
num = ;//初始化
BFS(dx, dy);
printf("%d\n",num);
}
return ;
}

  这里暂时整理出了此题的关于DFS和BFS算法的代码,DFS相对好理解,递归的思想早有接触,相对易用;BFS还涉及到queue队列的知识,初学时理解困难,即使此处整理出,也不能保证下次遇到时还能写的出来。

  代码一用的是并查集的思想,因为第一次做这个题目的时候刚学并查集,新鲜就拿出来用了,确实是磨破了头皮,尤其当看到DFS的代码以后,我现在再拿出来都不敢相信这是我当时写的代码?并查集的思想需要掌握,但是遇题还是要先判断清楚类型,选择相对简易方便、以及自己掌握熟练的算法。

  代码二是在模糊地听完了DFS和BFS以后写出来的代码,也是我现在最能接受的简易代码,递归的运用关键在于准确找到前后的联系,递归的代码看上去简单,但是真的遇到新题,可就有的折腾了。这类题型中不管DFS还是BFS都有相似的check部分,即在走出下一步之前,要判断将要走的点,是否在给定范围之内(也有可能在自己的数组中越界),并有相关标记,表示此处来过,避免重复计数,防止递归或循环没有尽头。

  代码三是书上的BFS算法,应该是标准的“模板了”,现在关于vector、queue、map之类的STL序列容器理解不深,掌握不全,运用不好,就算抄模板,也要多练习相关题目,熟悉此类题型的技巧规则。queue的.front() .pop() .push()时运用BFS解决题目的重要操作,queue是解决最短路径的利器,此处体现不多。

(勤加练习,勤写博客)2020/1/18/21:28

BFS和队列的更多相关文章

  1. 【BFS+优先级队列】Rescue

    https://www.bnuoj.com/v3/contest_show.php?cid=9154#problem/I [题意] 给定一个n*m的迷宫,A的多个小伙伴R要去营救A,问需要时间最少的小 ...

  2. 图的广度优先/层次 遍历(BFS) c++ 队列实现

    在之前的博文中,介绍了图的深度优先遍历,并分别进行了递归和非递归实现.BFS 无法递归实现,最广泛的实现是利用队列(queue).这与DFS的栈实现是极其相似的,甚至代码几乎都很少需要改动.从给定的起 ...

  3. BFS 模拟队列(水题)

    BFS 这道题 觉得比较适合BFS新手入门写,也许大家都以为最入门 的BFS题是在二维图上搜索,但是这道题是线性搜索,更加简单 POJ 3278 Catch That Cow Time Limit:  ...

  4. 哈尔滨理工大学第七届程序设计竞赛初赛(BFS多队列顺序)

    哈尔滨理工大学第七届程序设计竞赛初赛https://www.nowcoder.com/acm/contest/28#question D题wa了半天....(真真正正的半天) 其实D题本来就是一个简单 ...

  5. 对比dfs与bfs的存储机制以及bfs与队列的关系

    dfs由于是利用递归进行遍历,所以每种情况在时空上不会出现冲突,所以可以利用数组将每种情况的各个元素的值进行存储(即存储当前位) 而bfs由于并不是利用递归,不能将每种情况的值进行不冲突地存储,但由于 ...

  6. bfs,队列

    bfs bfs=队列 队列的操作 头文件 #include<deque> 声明方法: 1.普通声明 queue<int>q; 2.结构体 struct node { int x ...

  7. BFS的队列

    按老师上课的话来总结,队列变化多端:   普通模板没有代价: 普通队列FIFO 01代价: 双端队列,单调队列 任意代价: 优先队列/堆,最短路SPFA/DIJKSTRA

  8. 图的遍历——BFS(队列实现)

    #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> ...

  9. 2601 电路维修 (双端队列bfs\优先队列bfs(最短路))

    描述 Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上.Rika的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障,导致无法启动. 电路板 ...

随机推荐

  1. BZOJ 4556(后缀数组+主席树求前驱后继+二分||后缀数组+二分+可持久化线段树)

    换markdown写了.. 题意: 给你一个1e5的字符串,1e5组询问,求\([l_1,r_1]\)的所有子串与\([l_2,r_2]\)的lcp 思路: 首先可以发现答案是具有单调性的,我们考虑二 ...

  2. 2019icpc南京网络赛 A The beautiful values of the palace(离线+树状数组)

    题意: (假设所有的点对应的值已经求出)给你一个1e6*1e6的矩阵,有m<=1e5个点有值,其余都为0 q<=1e5个询问,求子矩阵的权值和 思路: 根据二维差分,对于询问左下角(x1, ...

  3. HDU 1005 Number Sequence(矩阵快速幂,快速幂模板)

    Problem Description A number sequence is defined as follows: f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1 ...

  4. centos7.5优化系统脚本(虚拟机下)

    #!/usr/bin/bash #安装常用软件,首先必须自行调整好网卡配置文件,保证可以上网,否则,下列优化会失败 yum -y install wget vim lrzsz bash-complet ...

  5. Flutter Widgets 之 FutureBuilder

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 展示异步任务状态 当有一个Future(异步)任务需要展示 ...

  6. mac下搭建http服务器(apache+php),使用homebrew升级php

    新版mac依旧预装了 Apache ,但是已经不能在 「系统偏好设置」中的「Web 共享」来开启了,需要手动通过命令行开启. 启动Apache 启动:sudo apachectl start 停止:s ...

  7. 五分钟了解抽象语法树(AST)babel是如何转换的?

    抽象语法树 什么是抽象语法树? It is a hierarchical program representation that presents source code structure acco ...

  8. Android Studio安装虚拟机步骤

    1. 新建 或者 2. 按图中的步骤,选择一款设备,建议选择分辨率小的,不占内存 3. 按图 4. 按图 5. 点击finish后,选择之前下载的虚拟机,点next 6. 虚拟机重命名 7. 到这里, ...

  9. 使用 linux kernel +busybox 定制linux系统

    目的: 了解linux的启动过程 主要内容: 1.grub 是启动程序的bootloader 2.linux-kernel 是linux的开源内核 3.busybox 是linux的工具集合 启动顺序 ...

  10. #《Essential C++》读书笔记# 第五章 面向对象编程风格

    基础知识 继承机制定义了父子(parent/child)关系.父类(parent)定义了所有子类(children)共通的共有接口(public interface)和私有实现(private imp ...