广度优先搜索算法的基本思想:
1、对于初始状态入队,设置初始状态为已访问
2、如果队列不为空时,出队队头元素,否则跳到第5步
3、检查出队的元素是否为最终解,如果是则跳到第5步。
4、对于出队的元素,检查所有相邻状态,如果有效并且未访问,则将
所有有效的相邻状态进行入队,并且设置这些状态为已访问,然后
跳到第2步重复执行
5、检查最后出队的元素是否为最终解,如果是输出结果,否则说明无解
广度优先搜索是借助于队列这种数据结构进行搜索的,队列的特点是先
进先出(FIFO),通过包含queue这个队列模板头文件,就可以利用c++
的队列模板定义自己的队列了,队列的操作非常简单,主要有以下几个:
q.push() 入队操作
q.front() 取队头元素
q.pop() 队头元素出队
q.size() 获取队列的元素个数
q.empty() 判断队列是否为空,为空返回true,不为空返回false
广度优先搜索算法的关键是要搞清楚求解过程中每一步的相邻状态有哪些,
每个状态需要记录什么信息,在搜索过程中如何标记这些状态为已访问。
在本题中,相邻状态为当前所在楼层通过按向上或向下按钮所能到达的楼
层,每个状态要记录的信息包括楼层编号和按按钮的次数。
代码如下:
#include<bits/stdc++.h>//bfs 上楼梯
using namespace std;
int n, start, end_;
vector<int>a, vis;
struct pos
{
int level, step;//楼层 步数
};
void bfs()
{
pos cur, nex;
cur.level = start;//这一行和下一行都是结构体初始化
cur.step = 0;
queue<pos>qu;//定义一个结构体队列
qu.push(cur);//将cur插入pos队列 (目前不知道为什么插入cur)
vis[start] = 1;//令出发点为1表示访问过
while (qu.empty()==false)//判断队列是否为空
{
cur = qu.front();//访问队列首元素
qu.pop();//删除队列首元素
if (cur.level == end_)//当达到目标楼层就输出步数并返回
{
cout << cur.step << '\n';
return ;
}
nex.level = cur.level + a[cur.level];//上升
nex.step = cur.step + 1;//增加步数
if (nex.level <= n)
{
if (vis[nex.level] == 0)
{
vis[nex.level] = 1;//标记已访问
qu.push(nex);//将当前楼层和步数插入队列
}
}
nex.level = cur.level - a[cur.level];//下降
nex.step = cur.step + 1;//增加步数
if (nex.level >= 1)
{
if (vis[nex.level] == 0)
{
vis[nex.level] = 1;//标记已访问
qu.push(nex);//将当前楼层和步数插入队列
}
}
}
cout << "-1" << '\n';//无法到达目标楼层
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while (cin >> n)
{
a.resize(n + 1);
vis.resize(n + 1);
if (n == 0)
break;
cin >> start >> end_;
for (int i = 1; i <= n; i++)//n层楼
{
cin>>a[i];//a数组保存ki
vis[i] = 0;
}
bfs();
}
return 0;
}