题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i 层楼(1 ≤ i ≤ N)上有一个数字Ki(0 ≤ K~i ≤ 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。
输入输出样例
输入 #1复制
5 1 5
3 3 1 2 5
输出 #1复制
3
思路
这显然是一道 bfs 的题了,需要注意的就是是否加入队列的判断条件,需要加一个数组,来判断这一楼层是否到过,因为要找最短路径嘛,肯定是在不同的楼层了,这样也避免了这一楼层数字为0,一直在这一个楼层和几个楼层来回去,不断循环的情况。
AC代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 205;
int n, a, b, flag, sum;
//arr数组用来存不同楼层的数字,pre数组用来存这一楼层的上一楼层
//例如pre[x] = y就是x的上一楼层是y,类似并查集中的,哈哈哈
int arr[N], pre[N];
int book[N];
queue<int> q;
//递归
void sumj(int x)
{
if(x == a){//终止条件
sum ++;
return;
}
x = pre[x];
sum ++;
sumj(x);
}
//bfs模板
void bfs()
{
q.push(a);
while(!q.empty()){
int t = q.front();
q.pop();
int x = t + arr[t];
int y = t - arr[t];
//大于0且小于n且这一楼层未访问过
if(x > 0 && x <= n && book[x] != 1){
//标记已经访问过
book[x] = 1;
q.push(x);
pre[x] = t;
if(x == b){
//标记已经找到
flag = 1;
break;
}
}
//大于0且小于n且这一楼层未访问过
if(y > 0 && y <= n && book[y] != 1){
//标记已经访问过
book[y] = 1;
q.push(y);
pre[y] = t;
if(y == b){
//标记已经找到
flag = 1;
break;
}
}
}
//如果没找到的话就输出 -1 了
if(flag == 0) printf("-1\n");
return;
}
int main(void)
{
scanf("%d%d%d",&n,&a,&b);
//如果起点和终点是同一个,直接就可以退出了,自然按按钮的次数为0
if(a == b){
printf("0\n");
return 0;
}
for(int i = 1; i <= n; i ++) scanf("%d",&arr[i]);
//bfs
bfs();
if(flag == 1){
//加和,判断按了几次按钮
sumj(pre[b]);
printf("%d\n",sum);
}
return 0;
}