【回溯】洛谷P1135奇怪的电梯

题目描述

呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 𝑖 层楼(1≤𝑖≤𝑁)上有一个数字 𝐾𝑖(0≤𝐾𝑖≤𝑁)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如: 3,3,1,2,5 代表了 𝐾𝑖(𝐾1=3,𝐾2=3,……),从 1楼开始。在 1 楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有 −2 楼。那么,从 𝐴楼到 𝐵 楼至少要按几次按钮呢?

输入格式

共二行。

第一行为三个用空格隔开的正整数,表示 𝑁,𝐴,𝐵(1≤𝑁≤200,1≤𝐴,𝐵≤𝑁)。

第二行为 𝑁 个用空格隔开的非负整数,表示 𝐾𝑖。

输出格式

一行,即最少按键次数,若无法到达,则输出 -1

输入输出样例

输入

5 1 5
3 3 1 2 5

输出

3

说明/提示

对于 100%的数据,1≤𝑁≤200,1≤𝐴,𝐵≤𝑁,0≤𝐾𝑖≤𝑁。


算法设计

本题解题的思路用到一个优化减枝的方法。

如上图所示,从A结点到绿色结点可以有一条长度为2的路径,也可以有一条长度为3的路径。

假设我们要找一条从A点——>绿色结点——>其他的路径,假设绿色结点——>其他路径长为x,那么从A点——>绿色结点——>其他的路径可以为2+x和3+x,我们显而易见的可知2+x必定比3+x更短。于是,在实际的搜索过程中,当我们搜索到a到绿色结点的路径为3<已知的2时,我们可以不必继续往下搜索。

函数设计

我们定义一个数组to[ ]来存放每个楼层上标记的数字

int to[MAX_N + 5];//每个楼层标记的数

//主函数
    scanf("%d%d%d", &n, &a, &b);
    for (int i = 1; i <= n; i++)scanf("%d",to+i);

定义数组dis[b]存储从起点到b的已知最短距离。在主函数中,我们给它最大的初始值。

我们定义函数dfs(int k,int a,int n),其中k表示到达a点的步数。如果当前的步数k大于dis[ ]数组中记录的已知最少步数,那么不必继续向下搜索,直接return。否则将k的值赋给dis[ ]数组。并继续向左右移动。

void dfs(int k, int a,int n) {//到达a点用了k步
    if (dis[a] <= k)return; 
    dis[a] = k;
    if (a + to[a] <= n)dfs(k + 1, a + to[a], n);
    if (a - to[a] >= 1)dfs(k + 1, a - to[a], n);
    return;
}

最后输出dis[b]中的值,即为a到b的最短步数。但是,如果dis[b]中的值依然是初始值n-1,则表示a到b不可达,输出-1。最后整理得到完整代码如下:

#include <string>
#include<map>
#include<set>
#include<vector> 
#include<iostream>

using namespace std;
#define MAX_N 200
int to[MAX_N + 5];//每个楼层标记的数
int dis[MAX_N + 5] = { 0 };//起点到每一个结点的已知最短距离

void dfs(int k, int a,int n) {//到达a点用了k步
    if (dis[a] <= k)return; 
    dis[a] = k;
    if (a + to[a] <= n)dfs(k + 1, a + to[a], n);
    if (a - to[a] >= 1)dfs(k + 1, a - to[a], n);
    return;
}
int main() {
    int n, a, b;
    scanf("%d%d%d", &n, &a, &b);
    for (int i = 1; i <= n; i++)scanf("%d",to+i);
    for (int i = 1; i <= n; i++)dis[i] = n + 1;
    dfs(0,a,n);
    printf("%d", dis[b] == n + 1 ? -1 : dis[b]);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值