P1135 奇怪的电梯

(提前声明,本篇博客可能质量不如前几篇好,毕竟连肝四篇博客我已经快吐血了✿◕‿◕✿)

看到这道题,第一时间想到的就是:深搜!!

于是我打了一个只能得到20分,剩下都MLE的深搜代码:

#include<iostream>
#include<cstdio>
using namespace std;
int n,m[210],a,b,xq=0,minn=9999;
void dfs(int idx,int cishu){
    if(idx==b){
        xq=1;//如果到达了我么就用小旗标记一下,以便于最后输出
        minn=min(minn,cishu);//每次到达想要的那个楼层时,都要取最小值,这样我们就可以得到只要要按几次按钮了。
        return;
    }
        //因为在每一层能做的操作只有两个,所以我们做两个判断就够了,如果不越界的话,进行深搜就好啦(●'◡'●)
    if(idx-m[idx]>0){
        dfs(idx-m[idx],cishu+1);
    }
    if(idx+m[idx]<=n){
        dfs(idx+m[idx],cishu+1);
    }
}
int main(){
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++){
        scanf("%d",&m[i]);
    }//以上全是输入
    dfs(a,0);//调用深搜函数
    if(xq!=0) printf("%d
",minn);//输出,如果小旗不等于零就说明我们到达过第b层楼
    else printf("-1
");//否则,也就是没有到达过第b层楼,就按照题目要求输出-1
    return 0;//不要忘记return 0喔
}    

MLE是什么来着?让我们百度一下:

看到这里你还不知道该干什么吗!俗话说,优化是个好东西

我们来用一个数组,把我们判断过的标记上,然后下次再判断到这个点我们就先看这个点有没有被标记,如果被标记了那也就不用继续下去了,反正已经判断过了。

    //数组定义个1000就好啦,反正数据也不大
    hh[idx]=1;//每次hh[idx]都等于1,然后后面进行深搜的时候它就不会被搜到喽,可以节省不少时间呢
    if(idx-m[idx]>0&&hh[idx-m[idx]]==0){//判断idx-m[idx]是否被算过
        dfs(idx-m[idx],cishu+1);//如果没有被计算过,那么idx-m[idx],次数+1啦
    }
    if(idx+m[idx]>0&&hh[idx+m[idx]]==0){//判断idx+m[idx]是否被算过
        dfs(idx+m[idx],cishu+1);//跟上面一样,如果没有被计算过,那么idx+m[idx],次数+1啦
    }
    hh[idx]=0;//最后不要忘了归零!很重要的!
    //如果你不归零会影响到后面计算,可能明明这一条路是最小的次数,结果就因为你忘了归零,成功错过正确答案

但是这样只有80分......我们还能怎么优化呢?

如果当前的次数已经大于minn了呢......那么继续算下去不久没有意义了?

那我们就再加一个判断条件:

   hh[idx]=1;
    if(idx-m[idx]>0&&cishu<minn&&hh[idx-m[idx]]==0){
        //加上这个特判就万事大吉了!如果当前次数已经大于等于minn那继续算下去就没有意义了,反正算到最后minn还是不变,所以我们只在当前次数小于minn的时候才算下去
        dfs(idx-m[idx],cishu+1);
    }
    if(idx+m[idx]>0&&cishu<minn&&hh[idx+m[idx]]==0){
        //这个跟上面那个道理是一样的啦
        dfs(idx+m[idx],cishu+1);
    }
    hh[idx]=0;

最后献上完整代码:

#include<iostream>
#include<cstdio>
using namespace std;
int n,m[210],a,b,xq=0,minn=9999,hh[1010];//minn不能等于很小,不然跟其他的比小他最小怎么办 
void dfs(int idx,int cishu){//深搜函数 
    if(idx==b){//出口,如果当前楼层就是第b层,那么就让小旗标记一下,取按键次数的最小值,然后返回 
        xq=1;
        minn=min(minn,cishu);
        return;
    }
    hh[idx]=1;//标记idx 
    if(idx-m[idx]>0&&cishu<minn&&hh[idx-m[idx]]==0){
        //次数如果大于等于minn那么计算下去就没意义了,反正算到最后minn不会有变化
        //如果hh数组的第idx-m[idx]项没有被标记,也就是说他没有被判断过,我们就可以继续了 
        dfs(idx-m[idx],cishu+1);//进行深搜,次数每次加一不要忘 
    }
    if(idx+m[idx]>0&&cishu<minn&&hh[idx+m[idx]]==0){//这个判断跟上一个是一样的,不过一个加一个减 
        dfs(idx+m[idx],cishu+1);//进行深搜,注意这里是+而不是- 
    }
    hh[idx]=0;//取消标记 
    return;//返回上一层
}
int main(){
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++){
        scanf("%d",&m[i]);
    }//以上为输入 
    dfs(a,0);//调用函数 
    if(xq!=0) printf("%d
",minn);//输出,小旗如果不等于0也就表示我们到达过第b层,输出minn就好了 
    else printf("-1
");//否则小旗等于0,也就是说我们从未到达过第b层,按照题目要求输出-1 
    return 0;
}

以上仅是个人对于这道题的全部思路与想法,如果有什么不对的地方,还请各位大佬及时向我纠正。

原文地址:https://www.cnblogs.com/dgdger/p/12887786.html