小U的最大连续移动次数问题 | 豆包MarsCode AI 刷题

130 阅读3分钟

小U的最大连续移动次数问题

问题描述

小U决定在一个 m×nm×n 的地图上行走。地图中的每个位置都有一个高度,表示地形的高低。小U只能在满足以下条件的情况下移动:

  1. 只能上坡或者下坡,不能走到高度相同的点。
  2. 移动时必须交替进行:上坡后必须下坡,下坡后必须上坡,不能连续上坡或下坡。
  3. 每个位置只能经过一次,不能重复行走。

任务是帮助小U找到他在地图上可以移动的最大次数,即在符合所有条件的前提下,小U能走过的最大连续位置数量。

例如在以下2x2的地图中:

1 2
4 3

中庸行者可以选择移动顺序 3 -> 4 -> 1 -> 2,最大移动次数为3。


测试样例

样例1:

输入:m = 2, n = 2, a = [[1, 2], [4, 3]]
输出:3

样例2:

输入:m = 3, n = 3, a = [[10, 1, 6], [5, 9, 3], [7, 2, 4]]
输出:8

样例3:

输入:m = 4, n = 4, a = [[8, 3, 2, 1], [4, 7, 6, 5], [12, 11, 10, 9], [16, 15, 14, 13]]
输出:11

解题思路

这道题目具有以下几个特点:

  • 搜索问题:每一步的选择依赖当前状态,因此 DFS 是合适的工具。
  • 分状态讨论:路径中存在两种状态:当前正在 上坡下坡
  • 剪枝优化:需要判断移动是否合法,减少无意义的搜索。

具体思路如下:

  1. 定义递归搜索函数

    • dfs(x, y, sta):表示小U当前在 (x,y)(x,y),并且状态为 sta(0 表示上坡,1 表示下坡)。
    • 从当前点出发,尝试向四个方向移动,找到所有符合条件的路径长度。
  2. 合法性检查

    • 确保移动后的位置在地图范围内。

    • 不能走回已经访问过的位置。

    • 判断高度关系是否符合当前状态要求:

      • sta = 0(上坡):目标点高度 > 当前点高度。
      • sta = 1(下坡):目标点高度 < 当前点高度。
  3. 记录与回溯

    • 使用 visited 数组记录已访问的位置,在递归结束后还原状态。
  4. 全局搜索

    • 枚举地图上的每一个点作为起点,并分别从两种状态(上坡/下坡)开始搜索,更新最长路径长度。

代码实现

以下是基于上述思路的完整代码实现:

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

// 四个方向移动
constexpr pair<int, int> dirs[] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

int solution(int m, int n, vector<vector<int>>& a) {
    // 记录访问状态
    vector<vector<int>> visited(m, vector<int>(n, 0));

    // DFS 搜索函数
    auto dfs = [&](auto&& self, int x, int y, int sta) -> int {
        int max_length = 0;
        for (auto [dx, dy] : dirs) {
            int nx = x + dx, ny = y + dy;
            // 判断合法性
            if (nx >= 0 && nx < m && ny >= 0 && ny < n && !visited[nx][ny]) {
                // 上坡状态:目标点高度必须更高
                if (sta == 0 && a[nx][ny] > a[x][y]) {
                    visited[nx][ny] = 1;
                    max_length = max(max_length, 1 + self(self, nx, ny, 1)); // 切换到下坡状态
                    visited[nx][ny] = 0;
                }
                // 下坡状态:目标点高度必须更低
                else if (sta == 1 && a[nx][ny] < a[x][y]) {
                    visited[nx][ny] = 1;
                    max_length = max(max_length, 1 + self(self, nx, ny, 0)); // 切换到上坡状态
                    visited[nx][ny] = 0;
                }
            }
        }
        return max_length;
    };

    int max_steps = 0;

    // 从每个点开始搜索
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            visited[i][j] = 1;
            max_steps = max(max_steps, dfs(dfs, i, j, 0)); // 从上坡开始
            max_steps = max(max_steps, dfs(dfs, i, j, 1)); // 从下坡开始
            visited[i][j] = 0;
        }
    }

    return max_steps;
}

int main() {
    vector<vector<int>> a1 = {{1, 2}, {4, 3}};
    cout << (solution(2, 2, a1) == 3) << endl;

    vector<vector<int>> a2 = {{10, 1, 6}, {5, 9, 3}, {7, 2, 4}};
    cout << (solution(3, 3, a2) == 8) << endl;

    vector<vector<int>> a3 = {{8, 3, 2, 1}, {4, 7, 6, 5}, {12, 11, 10, 9}, {16, 15, 14, 13}};
    cout << (solution(4, 4, a3) == 11) << endl;
}