当前位置:首页 > 牛客 > 牛客233065题:最长滑雪路径的动态规划与记忆化搜索解法

牛客233065题:最长滑雪路径的动态规划与记忆化搜索解法

6个月前 (08-27)

牛客233065题:最长滑雪路径的动态规划与记忆化搜索解法 动态规划 记忆化搜索 深度优先搜索 深搜 DFS 递归 C++ 牛客题解 第1张

一、题目解读

牛客233065题要求求解给定矩阵中的最长滑雪路径。滑雪者从任意点出发,每次只能向高度严格递减的相邻格子移动(上下左右四个方向),需找到路径长度最大值。题目考察动态规划与搜索算法的结合,重点在于优化重复计算以提高效率。

二、解题思路

采用深度优先搜索DFS)结合记忆化技术解决该问题。核心思路如下:

1. 记忆化搜索:为避免重复计算每个点的最长路径,使用二维备忘录记录已求解结果。

2. 递归式设计:从每个点出发递归搜索四周符合条件的低高度点,路径长度为其后继点最长路径+1。

3. 边界条件:严格检查矩阵边界及高度递减要求,确保路径合法性。

通过动态规划的思想,将递归搜索转化为有记忆的优化算法,显著降低时间复杂度。

三、解题步骤

1. 初始化:读取矩阵尺寸,创建与矩阵同大小的备忘录(全0表示未计算)。

2. 外层循环:遍历矩阵每个点作为起点,调用DFS函数更新最长路径结果。

3. DFS函数:

    若当前点已计算,直接返回备忘录值。

    遍历四个方向,对合法相邻点(边界内且高度递减)递归调用DFS,获取其最长路径。

    更新当前点的路径长度为所有后继点路径最大值+1,存入备忘录。

4. 结果汇总:外层循环结束后,备忘录中存储了所有点的最长路径,取全局最大值即为答案。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}}; // 四个方向

int dfs(vector<vector<int>>& matrix, vector<vector<int>>& memo, int i, int j) {
    if(memo[i][j]!= 0) return memo[i][j]; // 已计算过,直接返回结果
    
    int max_len = 1; // 至少包含自己
    for(auto& dir : dirs) { // 遍历四个方向
        int x = i + dir[0], y = j + dir[1];
        // 边界检查且高度必须严格递减
        if(x >= 0 && x < matrix.size() && y >= 0 && y < matrix[0].size() 
           && matrix[x][y] < matrix[i][j]) {
            max_len = max(max_len, dfs(matrix, memo, x, y) + 1);
        }
    }
    memo[i][j] = max_len; // 记忆化存储当前点的最长路径
    return max_len;
}

int longestSkiPath(vector<vector<int>>& matrix) {
    if(matrix.empty()) return 0;
    int n = matrix.size(), m = matrix[0].size();
    vector<vector<int>> memo(n, vector<int>(m, 0)); // 初始化备忘录
    int res = 0;
    
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < m; ++j) {
            res = max(res, dfs(matrix, memo, i, j)); // 更新全局最长路径
        }
    }
    return res;
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> matrix(n, vector<int>(m));
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < m; ++j) {
            cin >> matrix[i][j];
        }
    }
    cout << longestSkiPath(matrix) << endl;
    return 0;
}

五、总结

该解法巧妙地将动态规划思想融入DFS,通过备忘录消除递归中的重复计算,将时间复杂度优化至O(NM)(N为矩阵行数,M为列数)。代码结构清晰,边界处理严谨,是解决此类路径问题的典型范例。实际应用中,记忆化搜索常作为优化递归算法的有效手段,值得深入掌握。


原创内容 转载请注明出处

分享给朋友:

相关文章

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

题目重解我们面对一个经典背包问题的变体:给定n个物品,每个物品有重量w和价值v,背包容量为V。需要回答两个问题:1) 普通情况下能获得的最大价值;2) 必须恰好装满背包时的最大价值(若无法装满则输出0...

力扣654:递归分治的艺术 如何用最大元素构建二叉树

力扣654:递归分治的艺术 如何用最大元素构建二叉树

题目重解我们面对一个看似简单却充满递归魅力的题目:给定一个不含重复元素的整数数组,需要构建一棵特殊的二叉树。这个树的每个父节点都必须是当前子数组中的最大元素,而它的左右子树则分别由该最大值左侧和右侧的...

力扣540题:线性扫描法如何高效定位唯一数

力扣540题:线性扫描法如何高效定位唯一数

题目重解一个严格递增的有序数组中,除某个元素外,其余每个元素均出现两次。这个看似简单的条件背后隐藏着巧妙的规律——单一元素会打破数组的"成对对称性"。题目要求以O(log n)时间...

手搓顺序表类代码注释与详解:从零实现动态数组(新手教程)

一、简介和特点顺序表(Sequential List)是数据结构中基础的一种线性表,其特点是将数据元素存储在连续的内存空间中。通过数组实现,支持随机访问(即通过索引直接访问元素),适用于频繁随机读取的...

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

一、题目解读题目要求在一个n×m的网格中,从左上角到右下角选择一条路径,路径上的数字可重复取用,求取数之和的最大值。路径限制为仅能向右或向下移动。需注意路径的灵活性与重复取数的可能性,传统单向动态规划...

NOIP 2008火柴棒等式题解(C++代码实现)  动态规划与枚举算法详解

NOIP 2008火柴棒等式题解(C++代码实现) 动态规划与枚举算法详解

一、题目解读火柴棒等式问题(NOIP 2008,洛谷P1149)要求使用给定数量的火柴棒,构造形如 A + B = C 的等式,其中A、B、C均为整数,且火柴棒总数恰好等于输入值。需统计符合条件的等式...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。