【洛谷】【DFS】p1135:奇怪的电梯(C语言)

奇怪的电梯

题目描述

呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第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,结果好几个样例过不了,因为值太小了,步数更新不动

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

韬. .

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值