题目:
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 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。
约定:
对于 100% 的数据,1≤N≤200,1≤A,B≤N,0≤Ki≤N。
样例:
5 1 5
3 3 1 2 5
输出:
3
这个题目可以用广度优先算法来写,先上代码(c语言):
#include<stdio.h>
int main()
{
int n,h,i,m,g=0,l1,l2,o;
scanf("%d %d %d",&n,&h,&o);
int b[n],c[n],d[n],a[n];
for(i=0;i<n;i++)
{scanf("%d",&b[i]);
c[i]=0;}
a[0]=h-1;
c[h-1]=1;
d[h-1]=0;
for(m=1,i=0;i<m;i++)
{
if(a[i]==o-1) {printf("%d",d[o-1]);return 0;}
l1=a[i]+b[a[i]];
l2=a[i]-b[a[i]];
if(c[l1]==0&&l1<n)
{a[m++]=l1;d[l1]=d[a[i]]+1;c[l1]=1;}
if(c[l2]==0&&l2>=0)
{a[m++]=l2;d[l2]=d[a[i]]+1;c[l2]=1;}
}
printf("-1");
}
我写的代码并没有用标准的队列形式,数组a相当于队列,变量i,m分别为队列的头和尾。
其中,数组c用来标记已走过的楼层,数组d用来存储从初始楼层到某一楼层的最小路径,数组b用来存储电梯上的数字。n,h,o分别对应N,A,B。
ok,变量解释完了,接下来是对代码的分析(也算是让我重温一下)。
首先声明变量及数组。在读取数输入数组b的循环中,将数组c中的所有元素初始化为0。由于声明数组时只声明了n个元素,数组b也是b[0]开始赋值,因此a[0]要被赋值为h-1(最好)。同时,直接标记已访问楼层h,将d[h-1]赋值为0(因为是初始楼层且之后要参与运算)。
此后进入循环,循环的终止条件为i<m,因为当能访问楼层全部访问过时,m不会再增加,此时要结束循环。我在代码中用循环分割了两种结果。如果当前楼层时要找的楼层,那么直接输出d[o-1],并且用return 0结束函数;如果i=m,即能访问的楼层全访问完后还没找到目标楼层,那么说明无法到达目标楼层,结束循环输出-1。
l1,l2分别为上下楼层,在后续的两if语句中检查楼层是否被访问过,如果没被访问过且合法,就将其加入队列,后续i++会访问这些楼层。(这里我直接标记访问了,也可以在if语句上方标记访问,可以少写一点代码,总体没区别)。同时将上(下)楼层对应的数组d中的元素赋值为当前楼层对应的数组d中的元素加一,因为数组d中的元素是对应楼层到初始楼层所要按的按钮次数(最少),那么下一个楼层要按的按钮次数等于当前楼层到初始楼层的所要按的按钮次数(最少)加一,由于是从初始楼层一步步循环上来(感觉有点像递归),所以在逻辑上是成立的。
总结:
之前知道了广度搜索大概是怎么回事,但自己写的时候没想到用数组d来存次数(主要是没想到对应的逻辑,感觉还是递归这方面有所欠缺,得多仔细想想),最后还是去搜视频看了看才知道怎么做。