深度优先搜索(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. Java实现多线程下载,支持断点续传

    完整代码:https://github.com/iyuanyb/Downloader 多线程下载及断点续传的实现是使用 HTTP/1.1 引入的 Range 请求参数,可以访问Web资源的指定区间的内 ...

  2. python 类 - 继承

    继承 什么是继承? 编写类时,并非总要从空白开始.如果要编写的类是另一个现成类的特殊版本,可使用继承. 一个类继承另一个类时,将自动获得另一个类的所有属性和方法.现有的类称为父类,而新类称为子类. 子 ...

  3. python3 控制结构知识及范例

    (一)三种基本控制结构 1.顺序结构:按照程序语句编写的顺序依次逐条执行 2.选择结构:根据特定的条件选择某一个分支 3.循环结构:反复执行某个或者某些操作,关注点:在什么情况下,反复执行哪一部分的操 ...

  4. Codeforces_798

    A.暴力把每个位置的字符改成另外25个字符,判断是否回文. #include<bits/stdc++.h> using namespace std; string s; int main( ...

  5. WampServer 更换 mysql

    下载另外版本的mysql,复制到 wamp/bin,初始化号 修改wamp 的/wampmanager.conf 复制相关配置文件 [mysqloptions] mysqlPortUsed = &qu ...

  6. 重读es6, 正确了解promise中catch的用法

    前言 在最近的项目中,用到了es6的promise语法,发现promise.prototype.catch 并不只是单单reject抛出的回调函数,所以今天做一些笔录,防止以后在项目中又碰到这样的问题 ...

  7. 031.Python类中的方法

    一 类中的方法 1.1 介绍 (1) 普通方法(2) 绑定方法 绑定到对象 (自动传递对象参数) 绑定到类 (自动传递类参数) (3) 静态方法 (无论类还是对象,都可以调用) class Plane ...

  8. Hadoop fs 使用方法

    hdfs的基本命令 hdfs dfs -help    查看帮助 在HDFS的文件系统中,HDFS只支持绝对路径 1.-ls: 显示目录信息 hadoop fs -ls / 列出指定目录下的内容 2. ...

  9. javascript 原生js对html元素的 增删改查 操作

    'use strict'; class View{ constructor(){ } //创建html元素 addEl(fel, elemName, id, cls){ //创建一个元素 let el ...

  10. windows运行shell脚本

    1. 环境变量的理解:快速找到程序并执行,配置在path的目录下有系统环境和用户环境,配置在此的只要目录路径就好,在cmd输入名字就会去此路径找匹配程序执行 2. 将git安装目录下的....\Git ...