BFS算法经常需要用到队列辅助,如二叉树的层次遍历。
下面简单回顾一下队列的使用:
#include <queue>
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
queue<int> q;
q.push(1);
q.push(3);
q.push(5);
q.pop();
int a = q.front();
int b = q.back();
int c = q.size();
int d = q.empty();
cout << a << " " << b << " " << c << " " << d << " " << endl;
//cout : 3 5 2 0
return 0;
}
然后简单回顾一下图的层次遍历算法(宽度优先搜索),对于这里不了解的同学请在数据结构中学习相关内容。对于下图,其层次遍历序列为:1 2 3 4 5 6 7(从上往下,从左往右)
层次遍历算法思想:维护一个队列,用于存放节点的信息。当访问到一个节点的时候,先访问该节点,然后将该节点的左右儿子分别入对列。
层次遍历算法模板:
下面以一个例子加深BFS算法的理解:
有一个奇怪的电梯,他可以停在任何一层,并且在每个楼层有一个Ki(0<= Ki<=
N)。电梯只有两个按钮:上、下。当你在第i层,如果你按下“UP”按钮,你将上升Ki层,也就是说,你将会到达第i+Ki层,如果你按下“DOWN”按钮,你会下降Ki层,即您将前往第i-Ki层。当然,电梯不能高于N,也不能低于1。例如,有5层的建筑物,并且k1=3,k2=3,k3=1,k4=2,k5=5。从1楼开始,你可以按下“UP”按钮,你会到4楼,但如果你按下“DOWN”按钮,电梯不做处理,因为它不能下到-2楼。
问:当你在A楼而想去B楼时,至少须按下“UP”或“DOWN”按钮多少次?其中,1<= N,A,B <= 200
分析:
- 假如当前某人处在第5层且第5层的数字为2,那么如果按下“UP”按钮,他可以去到第7层,按下“DOWN”按钮他可以去到第3层。
- 同理,如果第7层的数字为1,在第7层按下“UP”按钮,他可以去到第8层,按下“DOWN”按钮他可以去到第6层。
- 如果第3层的数字为2,他可以去第1层和第5层。
- 最终可以画出如下所示的状态转移图
- 从下图可以得到,从第5层到第3/7层只需要1步,从第5层到第1/6/8层需要2步… …
下面是本题的AC代码及详细注释
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
using namespace std;
int n,Start,End; //n表示楼层高度
int k[205]; //存储每层的数
int vis[205]; //标记数组,记录当前楼层是否来过,初始为0
struct pos//结构体
{
int level;//当前在哪一层
int step;//当前已经行走的步数
};
void bfs()//宽搜,搜索到目标level时输出其对应的step
{
memset(vis,0,sizeof vis);//每次都需要重置状态数组
pos cur,nex;//定义两个结构体分别表示当前和将要搜索的状态
cur.level = Start;
cur.step = 0;//当前在第start层且搜索0次
queue<pos> qu;//定义一个结构体类型的队列
qu.push(cur);//将当前状态入队,此时队列非空
vis[Start] = 1;//将当前楼层标记为被访问过
while (!qu.empty())//队列非空
{
cur = qu.front();//获得队首元素
qu.pop();//队首元素出队
if (cur.level == End)//搜索到目标level
{
cout << cur.step << endl;
return;
}
//按下"UP"
nex.level = cur.level + k[cur.level];
nex.step = cur.step + 1;
if (nex.level <= n)//下一个楼层不超过楼层总数且未被访问过
{
if (vis[nex.level] == 0)
{
vis[nex.level] = 1;//将下一个楼层标记为已经被访问过
qu.push(nex);
}
}
//按下"DOWN"
nex.level = cur.level - k[cur.level];
nex.step = cur.step + 1;
if (nex.level >= 1)//下一个楼层不小于1且未被访问过
{
if (vis[nex.level] == 0)
{
vis[nex.level] = 1;
qu.push(nex);
}
}
}
printf("-1\n");//循环完毕仍没搜索到结果
return;
}
int main()
{
while (cin >> n && n)
{
cin >> Start >> End;
for (int i = 1 ;i <= n;i++) cin >> k[i];
bfs();
}
return 0;
}