luogu1135_奇怪的电梯
时空限制 1000ms/128MB
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i 层楼 (1≤i≤N)上有一个数字 Ki(0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如: 3,3,1,2,5 代表了 Ki(K1=3,K2=3,…),从 111 楼开始。在 1 楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有 −2 楼。那么,从 A 楼到 B 楼至少要按几次按钮呢?
输入输出格式
输入格式:
共二行。
第一行为 3 个用空格隔开的正整数,表示 N,A,B(1≤N≤200,1≤A,B≤N)。
第二行为 N 个用空格隔开的非负整数,表示 Ki。
输出格式:
一行,即最少按键次数,若无法到达,则输出 −1。
输入输出样例
输入样例#1:
5 1 5
3 3 1 2 5
输出样例#1:
3
代码
法一:STL队列
#include<iostream>
#include<queue>
using namespace std;
const int N = 205;
const int r[] = {1,-1};
int n,A,B,a[N];
struct node{
int floor,step;
node(){ }
node(int a,int b):floor(a),step(b){ }
};
queue<node> q;
bool visit[N];
int bfs(){
q.push(node(A,0)); //到A楼0步入队
visit[A] = true; //入队后标记
while (!q.empty()){ //队列非空
node t=q.front(); q.pop(); //取队头,队头出队
if (t.floor==B) return t.step; //到达楼层B
for (int i=0; i<2; i++){
int k=t.floor; //现在所在楼层
int x=k+r[i]*a[k]; //按按钮后能到达楼层
if (x>=1 && x<=n && !visit[x]){
q.push(node(x,t.step+1)); //到x楼t.step+1步入队
visit[x] = true; //入队后标记
}
}
}
return -1; //不能到达
}
int main(){
cin>>n>>A>>B;
for (int i=1; i<=n; i++) cin>>a[i];
if (A==B) cout<<0<<endl; //特判
else cout<<bfs()<<endl;
return 0;
}
法二:手动队列
#include<iostream>
using namespace std;
const int N = 205;
const int r[] = {1,-1};
int n,A,B,a[N],que[N*N][2],head,tail;
bool visit[N];
int bfs(){
que[++tail][0]=A; que[tail][1]=0; //到A楼0步入队
visit[A] = true; //入队后标记
while (head<tail){ //队列非空
head++; //取队头,队头出队
if (que[head][0]==B) return que[head][1]; //到达楼层B
for (int i=0; i<2; i++){
int k=que[head][0]; //现在所在楼层
int x=k+r[i]*a[k]; //按按钮后能到达楼层
if (x>=1 && x<=n && !visit[x]){
que[++tail][0]=x; que[tail][1]=que[head][1]+1; //到x楼que[head][1]+1步入队
visit[x] = true; //入队后标记
}
}
}
return -1; //不能到达
}
int main(){
cin>>n>>A>>B;
for (int i=1; i<=n; i++) cin>>a[i];
if (A==B) cout<<0<<endl; //特判
else cout<<bfs()<<endl;
return 0;
}