信奥赛C++提高组csp-s之搜索进阶(记忆化搜索案例实践1)

信奥赛C++提高组csp-s之搜索进阶(记忆化搜索案例实践1)

滑雪

题目描述

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

plain 复制代码
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 24-17-16-1 24−17−16−1(从 24 24 24 开始,在 1 1 1 结束)。当然 25 25 25- 24 24 24- 23 23 23- ... \ldots ...- 3 3 3- 2 2 2- 1 1 1 更长。事实上,这是最长的一条。

输入格式

输入的第一行为表示区域的二维数组的行数 R R R 和列数 C C C。下面是 R R R 行,每行有 C C C 个数,代表高度(两个数字之间用 1 1 1 个空格间隔)。

输出格式

输出区域中最长滑坡的长度。

输入输出样例 1
输入 1
复制代码
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
输出 1
复制代码
25
说明/提示

对于 100 % 100\% 100% 的数据, 1 ≤ R , C ≤ 100 1\leq R,C\leq 100 1≤R,C≤100。

思路分析

题目大意

在一个 R×C 的整数矩阵中,找一个点从该点出发,向上下左右四个方向滑行,只能滑向高度严格递减的相邻格子。求最长的滑行路径长度。

分析思路

如果用暴力DFS,每个点都要重新搜索,会导致大量重复计算。例如,从点A出发搜索到点B的路径时,已经计算过点B出发的最长路径长度;当从点C再经过点B时,又需要重新计算点B的路径,这就是重复计算。

记忆化搜索的做法:

  1. 定义 f[i][j] 表示从点 (i, j) 出发能滑行的最长路径长度
  2. 从每个点出发向四个方向DFS,如果邻点高度小于当前点,则递归求邻点的最长路径
  3. 取四个方向的最大值 + 1(当前点自身)
  4. 每计算完一个点,就把结果存入 f[i][j],下次再访问该点直接返回
时间复杂度

每个点只被访问一次,O(R×C)。

代码实现

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N = 105;  // 最大矩阵尺寸
int n, m;  // n行 m列
int h[N][N];  // h[i][j]存储每个点的高度
int f[N][N];  // f[i][j]存储从(i,j)出发的最长路径长度,-1表示未计算
int dx[4] = {-1, 1, 0, 0};  // 上下左右四个方向的行偏移
int dy[4] = {0, 0, -1, 1};  // 上下左右四个方向的列偏移

int dfs(int x, int y) {
    // 如果当前点已经计算过,直接返回
    if (f[x][y] != -1) return f[x][y];
    
    int ans = 1;  // 当前点至少长度为1(自身)
    for (int i = 0; i < 4; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];
        // 边界检查 && 只能往低处滑(严格递减)
        if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && h[nx][ny] < h[x][y]) {
            ans = max(ans, dfs(nx, ny) + 1);
        }
    }
    // 存储结果并返回
    return f[x][y] = ans;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> h[i][j];
        }
    }
    
    // 初始化备忘录,-1表示未访问过
    memset(f, -1, sizeof(f));
    
    int res = 0;
    // 枚举每个点作为起点,取最大值
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            res = max(res, dfs(i, j));
        }
    }
    
    cout << res << endl;
    return 0;
}

功能分析

模块 功能说明
备忘录数组 f[N][N] 存储每个点出发的最长路径长度,-1表示未计算,避免重复DFS
方向数组 dx[], dy[] 简化四个方向的遍历代码
dfs(x, y) 核心递归函数,返回从 (x,y) 出发的最长滑行长度
边界检查 确保不会走出矩阵范围
高度递减判断 只能向高度更低的格子滑,保证不形成循环
枚举所有起点 因为不知道最长路径从哪个点开始,所以每个点都要尝试

正确性保证:由于只能向更低处滑,不会形成环路,DFS终将终止,且每个状态只计算一次,不会超时。


更多系列知识,请查看专栏:《信奥赛C++提高组csp-s知识详解及案例实践》:

https://blog.csdn.net/weixin_66461496/category_13113932.html


各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}

1、csp信奥赛高频考点知识详解及案例实践:

CSP信奥赛C++动态规划:

https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转

CSP信奥赛C++标准模板库STL:

https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转

信奥赛C++提高组csp-s知识详解及案例实践:

https://blog.csdn.net/weixin_66461496/category_13113932.html

2、csp信奥赛冲刺一等奖有效刷题题解:

信奥赛C++普及组csp-j初赛&复赛真题题解(持续更新) https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新)

https://blog.csdn.net/weixin_66461496/category_13125089.html

3、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):

https://blog.csdn.net/weixin_66461496/category_13117178.html

4、csp/信奥赛C++,完整信奥赛系列课程(永久学习):

https://edu.csdn.net/lecturer/7901 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
落羽的落羽1 小时前
【项目】JsonRpc框架——功能测试、项目总结
linux·服务器·开发语言·c++·qt·算法·机器学习
Lucis__1 小时前
图的高阶算法:从构造最小生成树到求解最短路径问题
数据结构·c++·算法·图论
好评1249 小时前
【C++】智能指针全解
c++·智能指针
是阿建吖!10 小时前
【Linux】信号
android·linux·c语言·c++
城北徐宫10 小时前
Linux信号深度解剖:5种产生、3张表、4次切换
linux·c++·学习
liulilittle10 小时前
论 Linux 内核态全局稳态带宽的卡尔曼估计与工程实现
linux·服务器·网络·c++·计算机网络·tcp·通信
XBodhi.10 小时前
Visual Studio C++ 语法错误: 缺少“;”(在“return”的前面)
开发语言·c++·visual studio
froyoisle12 小时前
CSP-J 历年复赛 T1 及解析(2019~2025)
数据结构·c++·算法·csp-j·csp·算法竞赛·信息学
basketball61612 小时前
C++ 高级编程:2. 基本线程池实现
java·开发语言·c++