机器人能量冒险(中等)

83 阅读5分钟

问题描述

小R设计了一款有趣的机器人,它每次移动时至少需要消耗一个能量值。假设当小R为机器人提供了 5 个能量值,它可以选择不动,也可以走 1 步,但它不会走超过 5 步。
小R希望机器人能够走到一个终点,该终点位于 N 个位置的最后一个位置。每个位置上都有一定的能量值,机器人每次消耗当前位置的能量值可以往前走几步,之后可以继续消耗新的位置的能量继续前进。如果某个位置的能量值为 0,机器人将无法再继续行动。
小R想知道,机器人是否有可能通过这些能量值移动到最后一个位置。你能帮他计算一下吗?


测试样例

样例1:

输入:n = 5 ,array = [2, 3, 1, 1, 4]
输出:'TRUE'

样例2:

输入:n = 5 ,array = [3, 2, 1, 0, 4]
输出:'FALSE'

样例3:

输入:n = 6 ,array = [1, 2, 3, 4, 0, 0]
输出:'TRUE'

以下是对该问题的详细分析:

一、问题理解

小 R 设计的机器人移动需要消耗能量,初始给定一定能量值后它有多种移动步数选择,但不超过给定能量值对应的步数。同时,路径上每个位置都有能量值,机器人消耗当前位置能量可继续前进,若某位置能量值为 0 则无法继续行动。我们需要判断机器人能否利用这些能量值移动到最后一个位置。

二、关键要素分析

  • 初始能量值:小 R 为机器人提供的初始能量值决定了机器人首次移动时的步数选择范围,它可以选择不动或在不超过该初始能量值对应的步数范围内移动。
  • 位置能量值:路径上每个位置所具有的能量值,是机器人后续能否继续前进以及前进多少步的关键因素。一旦某个位置能量值为 0,机器人在此处就会停滞不前。
  • 目标位置:即路径上的最后一个位置,判断机器人是否能到达该位置是整个问题的核心目标。

三、解题思路

可以通过深度优先搜索(DFS)或者动态规划的方法来解决此问题。

方法一:深度优先搜索(DFS)

  1. 定义递归函数

    • 设 dfs(i, energy) 为从位置 i 出发且当前拥有能量值为 energy 时,能否到达最后一个位置的判断函数。其中 i 表示当前所在位置,energy 表示当前剩余能量值。
  2. 递归边界条件

    • 当 i 等于路径长度 n 时,说明已经到达最后一个位置,返回 True
    • 当 i 大于 n 或者 energy 小于等于 0 或者当前位置能量值为 0 时,说明无法到达最后一个位置,返回 False
  3. 递归搜索过程

    • 对于当前位置 i,获取其能量值 array[i]。然后从 1 到 min(energy, array[i]) 进行循环,尝试不同的移动步数 step。对于每一个 step,递归调用 dfs(i + step, energy - step),如果其中有一次递归调用返回 True,则说明可以通过某种移动方式到达最后一个位置,此时当前递归函数也返回 True;如果所有尝试的移动步数对应的递归调用都返回 False,则说明从当前位置以当前能量值无法到达最后一个位置,当前递归函数返回 False

方法二:动态规划

  1. 定义状态

    • 设 dp[i] 表示能否到达位置 i,初始时 dp[0] = True(因为机器人从起始位置出发,默认可以到达起始位置),其他位置初始化为 False
  2. 状态转移方程

    • 对于每个位置 i(从 1 到 n - 1),遍历在它之前的所有位置 j(从 0 到 i - 1)。如果 dp[j] 为 True(即已经可以到达位置 j),并且从位置 j 到位置 i 的步数不超过位置 j 处的能量值(即 i - j <= array[j]),那么就将 dp[i] 设置为 True
  3. 最终判断

    • 最后判断 dp[n - 1] 的值,如果为 True,则说明可以到达最后一个位置,输出 TRUE;如果为 False,则说明无法到达最后一个位置,输出 FALSE

       public class Main {
      
          public static String solution(int n, int[] array) {
              // 初始化当前位置为 0
              int currentPosition = 0;
              // 循环直到到达最后一个位置或者无法前进
              while (currentPosition < n - 1) {
                  // 如果当前位置的能量值为 0,直接返回 FALSE
                  if (array[currentPosition] == 0) {
                      return "FALSE";
                  }
                  // 计算可以前进的最大步数
                  int maxSteps = array[currentPosition];
                  // 尝试从当前位置前进
                  for (int step = 1; step <= maxSteps && currentPosition + step < n; step++) {
                      // 如果能直接到达最后一个位置,返回 TRUE
                      if (currentPosition + step == n - 1) {
                          return "TRUE";
                      }
                  }
                  // 选择能前进最远的步数
                  int bestStep = 0;
                  for (int step = 1; step <= maxSteps && currentPosition + step < n; step++) {
                      if (array[currentPosition + step] > array[currentPosition + bestStep]) {
                          bestStep = step;
                      }
                  }
                  // 前进所选的步数
                  currentPosition += bestStep;
              }
              // 如果循环结束还没到达最后一个位置,返回 FALSE
              if (currentPosition == n - 1) {
                  return "TRUE";
              } else {
                  return "FALSE";
              }
          }
      
          public static void main(String[] args) {
              // Add your test cases here
      
              System.out.println(solution(5, new int[] { 2, 3, 1, 1, 4 }).equals("TRUE"));
              System.out.println(solution(5, new int[] { 3, 2, 1, 0, 4 }).equals("FALSE"));
          }
      }