当前位置: 首页 > article >正文

P1135 奇怪的电梯(深度优先搜索优化)

题目描述

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

输入格式

共二行。

第一行为三个用空格隔开的正整数,表示 N,A,B(1≤N≤200,1≤A,BN)。

第二行为 N 个用空格隔开的非负整数,表示 K**i

输出格式

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

输入输出样例

输入

5 1 5
3 3 1 2 5

输出

3

说明/提示

对于 100% 的数据,1≤N≤200,1≤A,BN,0≤K**iN

本题共 16 个测试点,前 15 个每个测试点 6 分,最后一个测试点 10 分。

代码如下:

#include <bits/stdc++.h>
using namespace std;

vector<int> myOne;    // 存储每层楼的 K_i 值
int nn;               // 总楼层数 N
int min_count = 1e9;  // 记录最少按键次数,初始设为极大值
int A, B;             // 起始楼层 A 和目标楼层 B
bool flag = false;    // 标记是否找到可行解
vector<bool> v;       // 标记楼层是否被访问过,防止循环
vector<int> best;     // best[i] 表示到达 i 层时的已知最小按键次数,用于剪枝优化

// 深度优先搜索函数,x 是当前楼层,count 是已按的次数
void dfs(int x, int count) {
    // 剪枝1:当前按键次数已超过已知的最小值,无需继续搜索
    if (count >= min_count)
        return;
    // 剪枝2:当前到达 x 层的次数不比之前记录的更优,无需继续
    if (count >= best[x])
        return;
    best[x] = count;  // 更新到达 x 层的最优解

    // 边界检查:楼层超出有效范围
    if (x < 1 || x > nn)
        return;

    // 到达目标楼层,更新最小次数和标记
    if (x == B) {
        flag = true;
        min_count = min(count, min_count);
        return;
    }

    // 尝试向上移动:计算新楼层 next_up
    int next_up = x + myOne[x];
    if (next_up <= nn && !v[next_up]) {  // 检查是否越界且未被访问
        v[next_up] = true;               // 标记为已访问
        dfs(next_up, count + 1);        // 递归搜索
        v[next_up] = false;             // 回溯,取消标记
    }

    // 尝试向下移动:计算新楼层 next_down
    int next_down = x - myOne[x];
    if (next_down >= 1 && !v[next_down]) {  // 检查是否越界且未被访问
        v[next_down] = true;
        dfs(next_down, count + 1);
        v[next_down] = false;
    }
}

int main() {
    cin >> nn >> A >> B;
    myOne.resize(nn + 1);      // 调整大小,下标从 1 开始
    v.resize(nn + 1, false);   // 初始化访问标记数组
    best.resize(nn + 1, 1e9);  // 初始化最优数组,默认值为极大值

    // 读取每层的 K_i 值
    for (int i = 1; i <= nn; i++) {
        cin >> myOne[i];
    }

    v[A] = true;      // 标记起始楼层已访问
    dfs(A, 0);        // 从起始楼层开始搜索,初始按键次数为 0

    if (!flag) {      // 未找到可行路径
        cout << -1;
    } else {          // 输出最少按键次数
        cout << min_count;
    }

    return 0;
}

解决思路

  1. 问题建模
    将电梯移动过程视为状态转换问题。每个状态由当前楼层和已按次数组成,目标是找到从 A 到 B 的最短路径(最少按键次数)。
  2. 深度优先搜索(DFS)
    从起始楼层 A 出发,递归尝试所有可能的向上/向下移动。每次移动后更新按键次数,并记录到达新楼层的最优解。
  3. 剪枝优化
    • 最优性剪枝:若当前路径的按键次数已超过已知的最小值,或到达某楼层时次数不比之前记录的更优,则提前终止该路径搜索。
    • 循环检测:通过访问标记数组 v 避免在同一路径中重复访问同一楼层,防止无限循环。
  4. 记忆化优化
    best 数组记录到达每层的最小按键次数。当后续搜索到达同一楼层但次数更多时,直接剪枝,避免重复计算。
  5. 边界处理
    检查楼层是否在有效范围内(1~N),确保移动的合法性。

http://www.kler.cn/a/567497.html

相关文章:

  • 多维模型数据库(OLAP)和列式数据库的区别
  • 【Qt QML】QML鼠标事件(MouseArea)
  • 【JAVA SE基础】抽象类和接口
  • 贪心算法 求解思路
  • 4-1.jvm的类加载
  • 485 多路信号采集,校验干扰问题
  • 机器学习预备知识
  • 基于springboot+vue的拼夕夕商城
  • GPT-4.5实际性能评测:实际探索
  • Java并发编程之可见性、原子性和有序性
  • C语言-7.函数
  • 6-1JVM的执行引擎处理
  • CF 109A.Lucky Sum of Digits(Java实现)
  • ffmpeg-static 依赖详解
  • 芯麦GC1277与0CH477驱动芯片对比分析:电脑散热风扇应用的性能优势与替代方案
  • 在线抽奖系统——管理员注册
  • 张量运算全解析
  • NO.22十六届蓝桥杯备战|一维数组|七道练习|冒泡排序(C++)
  • 量子计算如何提升机器学习效率:从理论到实践
  • 蓝桥杯2024年第十五届省赛真题-传送阵