BFS广度优先搜索
BFS简要介绍
广度优先搜索算法的基本思想(摘自洛谷博客奇怪的电梯题解,侵删):
- 对于初始状态入队,设置初始状态为已访问
- 如果队列不为空时,出队队头元素,否则跳到第5步
- 检查出队的元素是否为最终解,如果是则跳到第5步。
- 对于出队的元素,检查所有相邻状态,如果有效并且未访问,则将所有有效的相邻状态进行入队,并且设置这些状态为已访问,然后跳到第2步重复执行
- 检查最后出队的元素是否为最终解,如果是输出结果,否则说明无解
广度优先搜索是借助于队列这种数据结构进行搜索的,队列的特点是先进先出(FIFO),通过包含queue这个队列模板头文件,就可以利用c++的队列模板定义自己的队列了,队列的操作非常简单,主要有以下几个:
- q.push() 入队操作
- q.front() 取队头元素
- q.pop() 队头元素出队
- q.size() 获取队列的元素个数
- q.empty() 判断队列是否为空,为空返回true,不为空返回false
广度优先搜索算法的关键是要搞清楚求解过程中每一步的相邻状态有哪些,每个状态需要记录什么信息,在搜索过程中如何标记这些状态为已访问。
例题
传送门
题解
//洛谷P1135 奇怪的电梯
#include<iostream>
#include<queue> //队列头文件
using namespace std;
struct ST{
int ceng; //当前楼层
int ans; //电梯按钮按的次数
}; //结构体
queue<ST> q; //定义队列
int n,a,b;
int s[1000]; //记录电梯可上(下)多少层
int vis[1000]; //判断是否访问过
int main(){
ST e1,e2;
int i;
cin>>n>>a>>b;
for(int i=1;i<=n;i++){
cin>>s[i];
}
e1.ceng=a; //从当前层开始
e1.ans=0; //初始化按按钮次数为0
q.push(e1); //把数据塞进队列
vis[a]=1; //当前层访问过了
while(!q.empty()){ //队列不为空就bfs
e2=q.front(); //取队首
q.pop(); //删掉
if(e2.ceng==b) break; //到达就结束搜索
i=e2.ceng+s[e2.ceng]; //如果往上可以到达哪层
if(i<=n&&vis[i]==0){ //没访问过并且不超过楼高
e1.ceng=i; //当前层更新
e1.ans=e2.ans+1; //按钮次数更新
q.push(e1);
vis[i]=1; //访问过了
}
i=e2.ceng-s[e2.ceng]; //这里是往下走的
if(i>=1&&vis[i]==0){
e1.ceng=i;
e1.ans=e2.ans+1;
q.push(e1);
vis[i]=1;
}
}
if(e2.ceng==b) cout<<e2.ans; //到达输出次数
else cout<<"-1"; //没到就输出-1(第一次提交因为忘了这个wa一个点)
return 0;
}