跳至主要內容

滑雪问题

梁梦露2024年12月24日大约 4 分钟教学文档动态规划

滑雪问题

1. 题目描述:

Michael喜欢滑雪,这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:

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-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。

输入格式:

输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。

输出格式:

输出最长区域的长度。

输入样例:

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

2. 题目解析:

  1. 问题理解与状态定义
    题目给定了一个二维区域表示滑雪场,区域中每个点都有对应的高度值,滑雪者只能从一个点滑向其上下左右四个相邻且高度更低的点,目标是找出在这个区域中最长的可滑行滑坡长度(即经过的点数最多的滑行路径)。
    我们可以定义一个二维数组 dp[i][j] 来表示状态,其中 i 表示所在行的索引(取值范围是从 0 到 R - 1,R 为行数),j 表示所在列的索引(取值范围是从 0 到 C - 1,C 为列数)。dp[i][j] 的值代表从坐标为 (i, j) 的这个点出发,所能达到的最长滑行路径长度(也就是能经过的最多点数)。

  2. 状态转移方程推导
    对于状态 dp[i][j],我们需要考虑从它的四个相邻位置(上、下、左、右)转移过来的情况,来推导出状态转移方程:设当前点坐标为 (i, j),高度为 height[i][j],四个方向的偏移量可以用数组表示为 int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};(分别对应上、下、左、右方向)。
    对于每个方向 k(k 取值为 0 到 3):先计算出相邻位置的坐标,设相邻位置坐标为 (new_i, new_j),其中 new_i = i + dirs[k][0]new_j = j + dirs[k][1]。接着判断相邻位置是否在滑雪场区域范围内(即 0 <= new_i < R0 <= new_j < C),并且该相邻位置的高度要小于当前位置高度(即 height[new_i][new_j] < height[i][j])。如果满足上述条件,说明可以从相邻位置滑到当前位置 (i, j),此时 dp[i][j] 就可以尝试从 dp[new_i][new_j] 的基础上转移过来,更新 dp[i][j] 的状态值为:dp[i][j] = max(dp[i][j], dp[new_i][new_j] + 1)。这里加 1 是因为要算上当前位置 (i, j) 这一点,也就是从相邻位置滑过来后路径长度要加 1。如果遍历完四个方向后,dp[i][j] 还是初始值(通常初始化为 0),说明从这个位置出发没有可以滑行的相邻位置,那么 dp[i][j] 就为 1(自身算一个点,长度为 1)。

  3. 初始化
    初始化 dp 数组时,将所有元素都初始化为 0,因为一开始还没有计算各个位置的最长滑行路径长度,都处于未知状态:

vector<vector<int>> dp(R, vector<int>(C, 0));
#include <iostream>
// #include <cstring>  

const int MAXN = 1005; 
int row, col, maxLength;
int dx[] = {0, 0, -1, 1};
int dy[] = {-1, 1, 0, 0};
int arrayMatrix[MAXN][MAXN];
int dpMatrix[MAXN][MAXN];

// 简化后的坐标合法性检查函数
bool isInRange(int x, int y) {
    return x >= 1 && x <= row && y >= 1 && y <= col;
}

int solve(int a, int b) {
    if (dpMatrix[a][b]) return dpMatrix[a][b];
    int res = 1;
    for (int i = 0; i < 4; i++) {
        int newX = a + dx[i];
        int newY = b + dy[i];
        if (isInRange(newX, newY) && arrayMatrix[newX][newY] < arrayMatrix[a][b])
            res = std::max(res, solve(newX, newY) + 1);
    }
    return dpMatrix[a][b] = res;
}

int main() {
    std::cin >> row >> col;
    for (int i = 1; i <= row; i++) {
        for (int j = 1; j <= col; j++) {
            std::cin >> arrayMatrix[i][j];
            dpMatrix[i][j] = 0;  // 初始化dp数组
        }
    }
    maxLength = 0;
    for (int i = 1; i <= row; i++) {
        for (int j = 1; j <= col; j++) {
            maxLength = std::max(maxLength, solve(i, j));
        }
    }
    std::cout << maxLength << std::endl;
    return 0;
}
上次编辑于: 2024/12/24 15:26:39
贡献者: keep