广度优先搜索
- 广度优先搜索(BFS)和深度优先搜索(DFS)都是一种暴力的搜索方式,常用于解决图和树的遍历问题。
广搜概念:
广搜,即广度优先搜索(BFS),是一种在图论和树结构中常用的搜索算法。其基本思想是从起始点开始,逐层地向外扩展,以确保先探索当前层的所有节点,然后再探索下一层的节点。广搜的特点是系统地展开并检查图中的所有节点,直到找到结果为止,不考虑结果的可能位置。
- bfs看起来像是“并行运行”,不过在程序运行时是单机运行顺序,所以可以看作是在模拟并行计算。
- 一般在编写时,会用队列来进行具体的BFS的实现。
- BFS实现树示意图:FBGADICEH(默认优先遍历左子树)
- BFS在图中的实现(以从mark开始为例)mark-(alice-rob)-(bob-maria) 逐层遍历
例题分析
(解决图问题)
/*题目介绍:有一个长方形的房间,在红黑砖上上下左右移动,但不能到红砖上。计算他能到达的黑砖数。
输入:第一行w,h表示房间大小。.表示黑砖,#表示红砖。@表示黑砖上的人。
输出。这个人能到达的瓷砖数。
*/
/*
使用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,y;};
void bfs(int dx,int dy){
num=1;queue<node>q;
node start,next;
start.x=dx; start.y=dy;
q.push(start);//将初始点位放入队列中
while(!q.empty()){//以队列是否为空作为结束标准
start=q.front();//将开始点位为队列中的首元素
q.pop();//首元素出队
//cout<<"out"<<start.x<<start.y<<endl; //打印队列元素进行验证
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)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;
}
经典例题
奇怪的电梯
#include <bits/stdc++.h>
using namespace std;
struct Node {
int floor;//楼层
int presses;//按键次数
};
int bfs(int n, int a, int b, vector<int>& k) {
queue<Node> q;//创建一个队
vector<bool> visited(n + 1, false);//创建一个数组存放是否到过该楼层
q.push({a, 0});visited[a] = true;//其实楼层入队
// BFS算法
while (!q.empty()) {//一般套路,当队列数为0时
Node current = q.front();//记录下当前节点为队列的头结点
q.pop();//将当前节点出队
int currentFloor = current.floor;//定义当前楼层和按键次数的变量
int currentPresses = current.presses;
// 如果到达目标楼层,返回按键次数
if (currentFloor == b) {
return currentPresses;
}
// 计算可以到达的楼层,上不超顶,下不过地
int upFloor = currentFloor + k[currentFloor - 1];
int downFloor = currentFloor - k[currentFloor - 1];
// 如果上升后的楼层合法且未访问过,入队
if (upFloor <= n && !visited[upFloor]) {
q.push({upFloor, currentPresses + 1});
visited[upFloor] = true;
}
// 如果下降后的楼层合法且未访问过,入队
if (downFloor > 0 && !visited[downFloor]) {
q.push({downFloor, currentPresses + 1});
visited[downFloor] = true;
}
}
// 如果无法到达目标楼层,返回-1
return -1;
}
int main() {
int n, a, b;
cin >> n >> a >> b;
vector<int> k(n);
for (int i = 0; i < n; ++i) {
cin >> k[i];
}
// 调用BFS函数并输出结果
cout << bfs(n, a, b, k) << endl;
return 0;
}
总结
总体而言其实广搜其实很好理解,代码形成也比较模式化,但还是要多练习,明白其实的搜索函数的精髓。