AI刷题-T18 小U的最大连续移动次数问题 题解

116 阅读4分钟

整体思路概述

要解决小U在地图上移动以获取最大移动次数的问题,核心在于找出所有可能的移动路径,并从中挑选出长度最长的路径。由于地图上每个位置都可能是起始点,且从每个起始点出发都有多种移动选择,这就需要对各种可能性进行全面的探索。深度优先搜索(DFS)是一种非常适合处理此类路径探索问题的算法,它能够沿着一条路径尽可能深地搜索下去,直到无法继续,然后回溯到上一个节点,尝试其他可能的路径。

具体步骤分析

1. 初始化部分

boolean[][] visited = new boolean[m][n];
int maxCount = 0;
  • 创建一个与地图大小相同的二维布尔数组 visited,用于记录地图上每个位置是否已经被访问过。这是为了确保每个位置只能经过一次,符合题目要求。
  • 初始化一个变量 maxCount 为 0,用于存储找到的最大移动次数。

2. 遍历所有可能的起始位置

for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        maxCount = Math.max(maxCount, dfs(i, j, a, visited, true, 1));
        maxCount = Math.max(maxCount, dfs(i, j, a, visited, false, 1));
    }
}
  • 使用两层嵌套的 for 循环遍历地图上的每一个位置 (i, j)
  • 对于每个位置,分别以“下一步是上坡”(isUp = true)和“下一步是下坡”(isUp = false)两种情况调用 dfs 方法进行深度优先搜索。
  • 在每次调用 dfs 方法后,使用 Math.max 函数更新 maxCount,确保 maxCount 始终存储着当前找到的最大移动次数。

3. 深度优先搜索(DFS)方法

private static int dfs(int x, int y, int[][] a, boolean[][] visited, boolean isUp, int count) {
    int m = a.length;
    int n = a[0].length;
    visited[x][y] = true;
    int maxCount = count;
    int[] dx = {0, 0, 1, -1};
    int[] dy = {1, -1, 0, 0};
    for (int i = 0; i < 4; i++) {
        int newX = x + dx[i];
        int newY = y + dy[i];
        if (newX >= 0 && newX < m && newY >= 0 && newY < n &&!visited[newX][newY]) {
            if (isUp && a[newX][newY] < a[x][y]) {
                maxCount = Math.max(maxCount, dfs(newX, newY, a, visited, false, count + 1));
            } else if (!isUp && a[newX][newY] > a[x][y]) {
                maxCount = Math.max(maxCount, dfs(newX, newY, a, visited, true, count + 1));
            }
        }
    }
    visited[x][y] = false;
    return maxCount;
}
  • 参数说明
    • xy 表示当前所在位置的坐标。
    • a 是存储地图每个位置高度信息的二维数组。
    • visited 是用于记录位置访问状态的二维布尔数组。
    • isUp 表示上一步移动是否为上坡,用于判断下一步移动的合法性。
    • count 表示当前已经走过的位置数量。
  • 核心逻辑
    • 首先将当前位置 (x, y) 标记为已访问。
    • 初始化从当前位置开始能达到的最大移动次数 maxCount 为当前的移动次数 count
    • 定义四个方向的偏移量数组 dxdy,分别表示右、左、下、上四个方向。
    • 使用 for 循环遍历这四个方向,计算新位置的坐标 (newX, newY)
    • 检查新位置是否在地图范围内且未被访问过:
      • 如果上一步是上坡(isUp = true),且新位置的高度小于当前位置的高度,说明可以下坡移动,递归调用 dfs 方法,将 isUp 置为 false(表示下一步要下坡),并将移动次数加 1。
      • 如果上一步是下坡(isUp = false),且新位置的高度大于当前位置的高度,说明可以上坡移动,递归调用 dfs 方法,将 isUp 置为 true(表示下一步要上坡),并将移动次数加 1。
      • 在每次递归调用后,使用 Math.max 函数更新 maxCount
    • 最后将当前位置标记为未访问,这一步是回溯操作,以便后续其他路径可以访问该位置。
    • 返回从当前位置开始能达到的最大移动次数。

全部代码

    public static int solution(int m, int n, int[][] a) {
        boolean[][] visited = new boolean[m][n];
        int maxCount = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                maxCount = Math.max(maxCount, dfs(i, j, a, visited, true, 0));
                maxCount = Math.max(maxCount, dfs(i, j, a, visited, false, 0));
            }
        }
		 // System.out.println("maxCount:"+maxCount);
        // System.out.println("-----");
        return maxCount;
    }

    private static int dfs(int x, int y, int[][] a, boolean[][] visited, boolean isUp, int count) {
        int m = a.length;
        int n = a[0].length;
        visited[x][y] = true;
        int maxCount = count;
        int[] dx = {0, 0, 1, -1};
        int[] dy = {1, -1, 0, 0};
        for (int i = 0; i < 4; i++) {
            int newX = x + dx[i];
            int newY = y + dy[i];
            if (newX >= 0 && newX < m && newY >= 0 && newY < n &&!visited[newX][newY]) {
                if (isUp && a[newX][newY] < a[x][y]) {
                    maxCount = Math.max(maxCount, dfs(newX, newY, a, visited, false, count + 1));
                } else if (!isUp && a[newX][newY] > a[x][y]) {
                    maxCount = Math.max(maxCount, dfs(newX, newY, a, visited, true, count + 1));
                }
            }
        }
        visited[x][y] = false;
        return maxCount;
    }