做这道题的时候就感觉对bfs的运用上比之前顺手了很多,做出这道题理解又加深了。
题目如下:
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第ii层楼(1 \le i \le N)(1≤i≤N)上有一个数字K_i(0 \le K_i \le N)Ki(0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3, 3 ,1 ,2 ,53,3,1,2,5代表了K_i(K_1=3,K_2=3,…)Ki(K1=3,K2=3,…),从11楼开始。在11楼,按“上”可以到44楼,按“下”是不起作用的,因为没有-2−2楼。那么,从AA楼到BB楼至少要按几次按钮呢?
输入格式
共二行。
第一行为33个用空格隔开的正整数,表示N,A,B(1≤N≤200, 1≤A,B≤N)N,A,B(1≤N≤200,1≤A,B≤N)。
第二行为NN个用空格隔开的非负整数,表示K_iKi。
输出格式
一行,即最少按键次数,若无法到达,则输出-1−1。
输入输出样例
输入 #1复制
5 1 5 3 3 1 2 5输出 #1复制
3
拿到题目之后,先在草稿纸下写下了思路,初步写了一个完整的代码,交了之后ac20,然后发现我忘记考虑达不到目标点的情况,(这个故事告诉我们要认真审题先),改了之后ac30,发现还有情况没考虑到,最后改来改去,ac80,最后两个样例就是过不了,看了看题解,有一个用户的代码我没看,但是在展示代码之前他写的东西倒是对我很有启发,我就做了一下笔记!
休息了一下之后回来 改了一下结果输出的位置结果居然过了,然后检查之后我才发现该位置的时候我无意识的修改了一个地方输出的东西(后面的代码展示中已标注),然后也思考了原因,然后又把一些地方删除呀修改呀提交测试,优化了一些地方(有点像字面意思上的剪枝的操作嘛),写完整体看了一下,然后加了一些注释!这道题就算满意得过啦!
下面直接展示我的代码!
#include<stdio.h>
int n,start,end,k[210];//层数,起点,终点,每层对应的操作层数
int book[1000];//标记
struct quene//bfs用队列模拟,队列用结构体实现
{
int n;//当前层数
int s;//按键次数
} que[1000];
int main()
{
scanf("%d %d %d",&n,&start,&end);
for(int i=1; i<=n; i++)
scanf("%d",&k[i]);
//初始化空队列
int head=1,tail=1;
//起点入队
que[tail].n=start;
que[tail].s=0;
book[start]=1;
tail++;
while(head<tail)//队列不为空时
{
if(que[head].n == end)//如果此时已经到达目标层
{
break;//跳出while循环
}
int up=que[head].n+k[que[head].n];//按上到几楼
int down=que[head].n-k[que[head].n];//按下到几楼
if(up<=n && book[up] == 0)//如果不越界且未来过次层
{
que[tail].n=up;
que[tail].s=que[head].s+1;
book[up]=1;
tail++;
}
if(down>0&&book[down] == 0)//同上
{
que[tail].n=down;
que[tail].s=que[head].s+1;
book[down]=1;
tail++;
}
head++;//这样子才可以接着扩展下一个点噢
}//while循环什么时候结束:当up或down的层楼都不符合要求时,不会进入两个if循环
//此时tail就没有增加,就不会大于head,所以就会跳出循环噢
if(que[head].n == end)//注意这里不能写if(que[tail-1].n == end),因为如果上一次while循环up和down都在范围内的话,tail会加1两次(我思考了一下觉得是这个原因),我最后卡在ac80就是因为这里
printf("%d",que[head].s);
else
printf("-1");
return 0;
}