奇怪的电梯
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第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
解题思路
本题大意为在某一个楼层,你最多有两种选择,要么向上,要么向下,爬或下多少层是规定好的,求最少要几步才能到达目标楼层。本题实质就是求最短路,这里我选择用dfs即深度优先搜索算法来解决。
1.先用递归从初始楼层开始将所有能走的路全部走一遍过去,具体就是两个方向,上或者下
2.进行一些优化即剪枝,第一个肯定是判断有没有超边界,第二个肯定是判断到达目标楼层后的总步数有没有比之前的小(因为一个样例可能有好几种方法可以到达目标楼层,而我们要求的是最短的那一条路)第三个可能比较容易漏掉,即每一个节点再去判断之前是否有搜索过,如果有再判断到达这一层所用的次数是否比之前小,如果没有,就不用再搜下去了。如果漏掉了这一点,那么只有30分。测试结果如下图:
AC代码
#include<stdio.h>
int arr[210] = { 0 };//定义一个arr数组用来存每层楼上的数字,即Ki
int N, A, B;
long long countt = 1e10;//定义一个countt变量来存最终答案
long long int minn[210] = { 1e10 };//定义一个minn数组来存到达每一层楼的最小步数
long long int d = 0;
void master(long long int a, long long int b, long long int c)//递归函数
{//a是开始层数,b是目标楼层,c是走的步数
if (c >= minn[a])//如果大于等于到达当前楼层的最小步数就剪枝
return;
if (c >= countt)//如果大于等于现有最终总步数就剪枝
return;
if (a == b)//如果到达目标楼层就更新答案
{
countt = c;
return;
}
minn[a] = c;//更新到达当前楼层的最小步数
if (a + arr[a] <= N)//判断有没有超上边界
{
d = a + arr[a];//向上爬
if (d == A)//如果回到题目最开始给的开始层就剪枝
return;
master(d, B, c + 1);//层数更新,步数加一,进入新一轮递归
}
if (a - arr[a] >= 1)//判断有没有越下边界
{
d = a - arr[a];//向下爬
if (d == A)
return;
master(d, B, c + 1);
}
}
int main()
{
scanf("%d %d %d", &N, &A, &B);
for (int i = 1; i <= N; i++)
{
scanf("%d", &arr[i]);//循环读入Ki
minn[i] = 1e10;//将minn数组的每一个值都赋一个很大的初值,防止最小步数无法更新
}
master(A, B, 0);//递归开始,初始步数为0
if (countt != 1e10)//如果countt不等于一开始赋的初值,说明能到终点,输出答案
printf("%lld", countt);
else//否则输出-1
printf("-1");
return 0;
}
注意
这几个地方要开long long,并且赋上一个很大的值,如1e18
long long countt = 1e10;//定义一个countt变量来存最终答案
long long int minn[210] = { 1e10 };//定义一个minn数组来存到达每一层楼的最小步数
long long int d = 0;
minn[i] = 1e10;//将minn数组的每一个值都赋一个很大的初值,防止最小步数无法更新
我一开始用的int,并只赋了个1000000000,结果好几个样例过不了,因为值太小了,步数更新不动