奇怪的电梯(洛谷P1135)

前言&吐槽

  同样可以拿dfs,这道题怎么就难那么多呢?

题目描述

奇怪的电梯

 

 算法设计

dfs的基本框架就是遍历一个结点的每一条路,所以我们的算法大概可以设计成这样

void dfsInEveryFloor()
{
    if (当前楼层 == 目标楼层)
    {
        做一些操作...
        retrun;
    }
    
    if (满足电梯向上走的条件)
    {
        dfsInEveryFloor();
    }
    if (满足电梯向下走的条件)
    {
        dfsInEveryFloor();
    }
}

我们假设step是所求的最小次数,sum为某一条路需要的次数,那么可以知道:

  • 在一个结点处,无论向上还是向下,sum都应该加1,但是sum本身不应该改变,因为那样sum得出来就不是一条路的次数了,而是多条路的总次数
  • 如果达到了目标,就可以置step了
  • 如果sum已经大于step,那么这个路就已经不是最小的了,直接return结束递归

根据上述发现,我们将代码完善一下:

void dfsInEveryFloor(int now, int sum)
{
    if (now == targetFloor)
    {
        step = min(step, sum);  //sum与step的最小值
        return;
    }
    
    if (sum > step)
    {
        return;
    }
    
    if (now + floor[now] <= N)
    {
        dfsInEveryFloor(now + floor[now], sum + 1); //如果这里使用sum++,求的是两条路加起来的次数
    }
    if (now - floor[now] > 0)
    {
        dfsInEveryFloor(now - floor[now], sum + 1);
    }
}

但是这并不能解这道题,因为如果楼层的按钮为0的话,会造成无限递归

解决方案是,看看这条路的此结点有没有经过。

我们使用

bool floorState[205];    //因为楼层最多200

来保存状态

那么代码可以更改为

void dfsInEveryFloor(int now, int sum)
{
    if (now == targetFloor)
    {
        step = min(step, sum); // sum与step的最小值
        return;
    }

    if (sum > step)
    {
        return;
    }
    floorState[now] = 1;                                        //已经过
    if (now + floor[now] <= N && !floorState[now + floor[now]]) //下一个结点没经过
    {
        dfsInEveryFloor(now + floor[now], sum + 1); //如果这里使用sum++,求的是两条路加起来的次数
    }
    if (now - floor[now] > 0 && !floorState[now - floor[now]])
    {
        dfsInEveryFloor(now - floor[now], sum + 1);
    }

    floorState[now] = 0; //接下来要回溯到上一个结点走另一条路,此时已经是不同的路了,因此需要重置状态
}

到此为止,算法已经设计完了。接下来就进行实现吧

代码实现

#include <iostream>
using namespace std;
bool floorState[205] = {0};   //记录楼层状态(这条有没有被搜索)
int floorStep[205] = {0};
int N, A, B;
int step = 0x7fffff;

void dfs(int now, int sum)
{
    if (now == B)
    {
        step = min(step, sum);
    }
    //因为寻找的是最短路径
    if (sum > step)
    {
        return;
    }
    
    floorState[now] = 1;    //该层被搜索
    if (now + floorStep[now] <= N && !floorState[now + floorStep[now]])
    {
        dfs(now + floorStep[now], sum + 1);
    }
    if (now - floorStep[now] > 0 && !floorState[now-floorStep[now]])
    {
        dfs(now - floorStep[now], sum + 1);
    }
    //实际上上面那两个已经把当前楼层的情况搜完了
    //因此下面需要回溯到新的路径时,需要重置状态
    floorState[now] = 0;
}

int main()
{
    cin >> N >> A >> B;
    for (int i = 1; i <= N; i++)
    {
        cin >> floorStep[i];
    }
    dfs(A, 0);
    if (step != 0x7fffff)
    {
        cout << step;
    }
    else{
        cout << -1;
    }
    
}

  我也是才刚刚学DFS,若有不准确还请指出

posted @ 2022-03-19 15:12  帝皇の惊  阅读(401)  评论(0)    收藏  举报