奇怪的电梯(深搜+剪枝)

洛谷:奇怪的电梯

题目描述

呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第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。

输入样例

5 1 5
3 3 1 2 5

输出样例

3

思路:

暴力深搜+剪枝(注意回溯,取最少按键次数方案)

(代码附详细解释说明)

AC 代码:

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#define mod 998244353
#define Max 0x3f3f3f3f
#define Min 0xc0c0c0c0
#define mst(a) memset(a,0,sizeof(a))
#define f(i,a,b) for(int i=a;i<b;i++)
using namespace std;
typedef long long ll;
const int maxn=100005;
int n,a,b;
int ans=Max;
int arr[205];
bool vis[205];      //vis数组存储是否去过某楼层
void dfs(int sx,int sum){   //sx表示当前楼层,sum统计按键次数
    if(sx==b){              //到达目的楼层
        ans=min(ans,sum);   //取最优方案
    }
    else if(sum<=ans){      //最优剪枝:当前按键次数sum>ans,必不可能为最优方案
        vis[sx]=true;       //标记去过的楼层
        if(sx+arr[sx]<=n && vis[sx+arr[sx]]==false ){   //暴力深搜:上
            dfs(sx+arr[sx],sum+1);
        }
        if(sx-arr[sx]>=1 && vis[sx-arr[sx]]==false){    //暴力深搜:下
            dfs(sx-arr[sx],sum+1);
        }
        vis[sx]=false;              //回溯
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>a>>b;
    for(int i=1;i<=n;i++){
        cin>>arr[i];
    }
    memset(vis,false,sizeof(vis));
    vis[a]=true;    //记录来过初始楼层
    dfs(a,0);       //开始暴力深搜
    if(ans!=Max){   //判断是否能到达目的楼层
        cout<<ans<<endl;
    }
    else{
        cout<<"-1"<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq1013459920/article/details/82810739
今日推荐