P1135 奇怪的电梯
注:参考过网上代码,理解后写的,看的这位写的很清楚,表示感谢。
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第i层楼(1 ≤ i ≤ N))上有一个数字Ki(0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3,3,1,2,5代表了Ki(K1=3,K2=3,…),从1楼开始。在1楼,按“上”可以到4楼,按“下”是不起作用的,因为没有−2楼。那么,从A楼到B楼至少要按几次按钮呢?
输入格式
共二行。
第一行为3个用空格隔开的正整数,表示N,A,B(1≤N≤200,1≤A,B≤N)。
第二行为N个用空格隔开的非负整数,表示Ki。
输出格式
一行,即最少按键次数,若无法到达,则输出−1。
输入输出样例
输入
5 1 5
3 3 1 2 5
输出
3
思路
自己对于这个深度搜索和广度搜索不太熟悉这个题目对于练手也是很好的
深度搜索一层一层搜查,先把开始楼层结点的子节点(向上走的结点和向下走的结点)查一遍,然后再查子节点的结点。这样的话每一层的搜查步数也就对应层数。这样的话如果查到步数肯定是最少的。接下来看代码
代码
#include <iostream>
#include <queue>
using namespace std;
int n, a, b;//和题目中变量意义一致
int x[205];//最大数据范围200
queue< pair<int, int> > q;//广度搜索用的队列 队列的数据类型为简易结构体
pair<int, int> p, e;//简易结构体p是当前层 e是下一层 first是当前楼层数 second是步数
bool f[205];//判断楼层是否被访问过
int bfs()
{
p.first = a, p.second = 0;
q.push(p);//把第a层放入队列
f[a] = false;//访问过a然后把a标记为假
while ( !q.empty() )//队列不为空进行
{
p = q.front();//取出当前楼层
q.pop();//取出完毕 弹出队列
if(p.first == b)//如果为目标值则输出并且跳出循环
{
cout << p.second;
return 0;//这里说明有解则不用输出-1
}
if( p.first + x[p.first] <= n && f[p.first + x[p.first]])//上楼 判断范围并且判断是否被访问过
{
e.first = p.first + x[p.first];//对写入下一层的层数
e.second = p.second + 1;//步数加一
f[e.first] = false;//标记访问
q.push(e);//入队
}
//下楼同理
if( p.first - x[p.first] >= 1 && f[ p.first - x[p.first]])
{
e.first = p.first - x[p.first];
e.second = p.second + 1;
f[e.first] = false;
q.push(e);
}
}
return 1;//失败 没有方法 则if语句成立输出-1;
}
int main(void)
{
cin >> n >> a >> b;
for( int i = 1; i <= n; ++i)
{
cin >> x[i];
f[i] = true;//初始为真
}
if (bfs())//开始搜索
{
cout << -1;//(如果无法找到目标楼层就输出-1)
}
return 0;
}