题解:AcWing 901 记忆化搜索

【题目描述】

给定一个 \(R\)\(C\) 列的矩阵,表示一个矩形网格滑雪场。

矩阵中第 \(i\) 行第 \(j\) 列的点表示滑雪场的第 \(i\) 行第 \(j\) 列区域的高度。

一个人从滑雪场中的某个区域内出发,每次可以向上下左右任意一个方向滑动一个单位距离。

当然,一个人能够滑动到某相邻区域的前提是该区域的高度低于自己目前所在区域的高度。

下面给出一个矩阵作为例子:

 1  2  3  4 5

16 17 18 19 6

15 24 25 20 7

14 23 22 21 8

13 12 11 10 9

在给定矩阵中,一条可行的滑行轨迹为 \(24-17-2-1\)

在给定矩阵中,最长的滑行轨迹为 \(25-24-23-...-3-2-1\),沿途共经过 \(25\) 个区域。

现在给定你一个二维矩阵表示滑雪场各区域的高度,请你找出在该滑雪场中能够完成的最长滑雪轨迹,并输出其长度(可经过最大区域数)。

【输入】

第一行包含两个整数 \(R\)\(C\)

接下来 \(R\) 行,每行包含 \(C\) 个整数,表示完整的二维矩阵。

【输出】

输出一个整数,表示可完成的最长滑雪长度。

【输入样例】

5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9

【输出样例】

25

【解题思路】

image

【算法标签】

《AcWing 901 滑雪》 #动态规划# #记忆化搜索#

【代码详解】

// 引入所有标准库头文件,方便使用各种标准库功能
#include <bits/stdc++.h>

// 使用标准命名空间,避免每次使用标准库函数时都需要加 std:: 前缀
using namespace std;

// 定义常量
const int N = 305;  // 数组最大尺寸为305,适应300x300的网格数据

// 定义全局变量
int g[N][N];          // g[N][N]: 存储滑雪区域每个格子的高度
int f[N][N];          // f[N][N]: f[i][j] 表示从第i行第j列开始时的最大滑雪长度
int n;                // n: 滑雪格子的数量
int R, C;             // R: 滑雪区域的行数,C: 滑雪区域的列数

// 定义方向增量数组,用于四个方向的移动:上、右、下、左
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

// 定义结构体 Node,用于存储每个格子的属性:行、列、高度
struct Node {
    int r, c, h;  // r: 行,c: 列,h: 高度
};

// 定义 Node 类型的数组 a,用于存储所有滑雪格子的信息
Node a[N * N];  // a[N*N]: 存储所有滑雪格子的信息

// 定义比较函数 mycmp,用于按高度从小到大排序
bool mycmp(Node x, Node y)
{
    return x.h < y.h;
}

// 主函数,程序的入口点
int main()
{
    // 读取滑雪区域的行数 R 和列数 C
    cin >> R >> C;

    // 初始化滑雪格子的数量 n 为 1
    n = 1;

    // 双重循环读取滑雪区域每个格子的高度,并存储到数组 g 和 a 中
    for (int i = 1; i <= R; i++) 
        for (int j = 1; j <= C; j++) 
        {
            // 读取第 i 行第 j 列格子的高度
            cin >> g[i][j];

            // 将第 i 行第 j 列格子的信息(行、列、高度)存储到数组 a 中
            a[n++] = {i, j, g[i][j]};

            // 初始化从第 i 行第 j 列开始的最大滑雪长度为 1
            f[i][j] = 1;
        }

    // 修正滑雪格子的数量 n,因为最后一次循环导致 n 多加了 1
    n--;  

    // 按照高度从低到高的顺序对数组 a 中的格子进行排序
    sort(a + 1, a + n + 1, mycmp);

    // 定义临时变量 nx 和 ny,用于存储移动后的新行和新列
    int nx, ny;

    // 遍历排序后的所有格子,按照高度从低到高的顺序处理
    for (int i = 1; i <= n; i++) 
    {
        // 获取当前格子的行 x 和列 y
        int x = a[i].r;
        int y = a[i].c;

        // 遍历四个方向:上、右、下、左
        for (int j = 0; j < 4; j++) 
        {
            // 计算移动后的新行 nx 和新列 ny
            nx = x + dx[j];
            ny = y + dy[j];

            // 检查新行 nx 和新列 ny 是否在滑雪区域的合法范围内
            if (nx < 1 || nx > R || ny < 1 || ny > C) 
                continue;  // 如果不在范围内,跳过当前方向

            // 如果移动后的新格子的高度大于当前格子的高度,表示可以滑行
            if (g[nx][ny] > g[x][y]) 
                // 更新从新格子 nx, ny 开始的最大滑雪长度
                // 取当前值与新值 f[x][y] + 1 中的较大者
                f[nx][ny] = max(f[nx][ny], f[x][y] + 1);
        }
    }

    // 初始化变量 ans,用于存储整个滑雪区域中的最大滑雪长度,初始值为 1
    int ans = 1;

    // 遍历滑雪区域的所有格子,找出最大的滑雪长度
    for (int i = 1; i <= R; i++) 
        for (int j = 1; j <= C; j++) 
        {
            // 更新 ans 为当前格子 f[i][j] 和之前 ans 中的较大值
            ans = max(ans, f[i][j]);
        }

    // 输出整个滑雪区域中的最大滑雪长度
    cout << ans << endl;

    // 程序正常结束,返回 0
    return 0;
}

【运行结果】

5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
25
posted @ 2026-02-26 11:51  团爸讲算法  阅读(0)  评论(0)    收藏  举报