题目背景
感谢 @[yummy](https://www.luogu.com.cn/user/101694) 提供的一些数据。
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i 层楼(1≤i≤N)上有一个数字 Ki(0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3, 3, 1, 2, 5 代表了 Ki(K1=3,K2=3,……),从 1 楼开始。在 1 楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有 -2 楼。那么,从 A 楼到 B 楼至少要按几次按钮呢?
输入格式
共二行。
第一行为三个用空格隔开的正整数,表示 N, A, B(1≤N≤200,1≤A,B≤N)。
第二行为 $N$ 个用空格隔开的非负整数,表示 Ki。
输出格式
一行,即最少按键次数,若无法到达,则输出 `-1`。
输入 #1
5 1 5
3 3 1 2 5
输出 #1
3
说明/提示
对于100% 的数据,1≤N≤200,1≤A,B≤N,0≤Ki≤N。
本题共 16 个测试点,前15个每个测试点 6 分,最后一个测试点 10 分。
//思路//
这一题我用的是广搜(bfs),首先看我们所在的A楼是不是要求的B楼,然后通过while循环来看要坐几回电梯。
//代码//
#include<bits/stdc++.h> //万能头文件
using namespace std;
int n,a,b,k[205],ans[205],q[205],f,r,xx[3]={0,-1,1};
//楼层的总数n,最开始所在的楼层a,要去的楼层b,所有的楼层数字k数组,去每一个楼层按键次数ans数组,每一次去的楼层q数组,边界设置条件f和r,移动距离xx数组
bool bb[205]; //避免一直重复的bb数组
void bfs(int x) { //bfs函数
r++; //设定右边边界
q[r]=x; //在第r次时走的是x层(其实是上一个走过的楼层)
bb[x]=1; //x层走过了
ans[x]=0; //因为x层就是我们所在的楼层,所以次数是0
if(x==b) { //如果我们所在的楼层就是我们要去的楼层
cout<<ans[x]; //直接输出ans[x](0)
return ; //完毕
} //如果我们所在的楼层不是我们要去的楼层
while (f!=r) { //只要左边的边界不是右边的边界
f++; //左边边界向右
for (int i=1;i<=2;i++){//向下向上走一下
int nx=q[f]+xx[i]*k[q[f]];
//定义现在的位置nx,让它等于它的前一楼层减或加它的楼层数字
if (nx>=1&&nx<=n&&bb[nx]==0) {
//如果nx这一楼层存在,没有到地下或是超出最大楼层,并且没有走过
r++; //扩大右边边界
q[r]=nx; //将上一个走过的楼层更新成nx
bb[nx]=1; //nx楼层走过了
ans[nx]=ans[q[f]]+1;
//到达nx楼层是到它的前一楼层的次数加1
if(nx==b) { //如果要到达的楼层就是nx楼层
cout<<ans[nx];
//输出它的次数
return ; //完毕
}
}
}
}
cout<<"-1"; //搜到最后也没到达要到达的楼层,说明到达不了,输出-1
}
int main(){
cin>>n>>a>>b; //输入楼层的总数,最开始所在的楼层,要到达的楼层
for (int i=1;i<=n;i++) { //循环输入每一楼层的数字
cin>>k[i]; //存入k数组里
}
bfs(a); //开始坐电梯
return 0;
}