##[$AcWing$ $901$. 滑雪](https://www.acwing.com/problem/content/description/903/) ### 一、题目描述 给定一个 $R$ 行 $C$ 列的矩阵,表示一个矩形网格滑雪场。 矩阵中第 $i$ 行第 $j$ 列的点表示滑雪场的第 $i$ 行第 $j$ 列区域的高度。 一个人从滑雪场中的某个区域内出发,每次可以向上下左右任意一个方向滑动一个单位距离。 当然,一个人能够滑动到某相邻区域的前提是该区域的高度低于自己目前所在区域的高度。 下面给出一个矩阵作为例子: ```c++ 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$ 个整数,表示完整的二维矩阵。 **输出格式** 输出一个整数,表示可完成的最长滑雪长度。 **数据范围** $1≤R,C≤300$,$0≤矩阵中整数≤10000$ **输入样例**: ```cpp {.line-numbers} 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 ``` **输出样例**: ```cpp {.line-numbers} 25 ``` ### 二、分析过程 - 从某个点出发,我们通过$dfs$四个方向,不断的深度搜索,可以找到它的最长路径 - 下面假设以$(4,2)$为出发点,并且计算过最长路径为$24$ 依题意,只能从高度高的向高度低的滑行,所以如果我们选择了出发点$(4,3)$,假设它向比它低的位置$(4,2)$滑过去,那么$(4,2)$的最长距离不用重新计算,直接使用$24$即可,因为这个距离不会因为你选择了其它更高的起点而变化。 ### 三、实现代码 ```cpp {.line-numbers} #include using namespace std; const int N = 310; int dx[] = {-1, 0, 1, 0}; int dy[] = {0, 1, 0, -1}; int g[N][N]; // 邻接矩阵,地图 int f[N][N]; // 记录从i到j的最大距离 int n, m; // 行与列 int res; // 结果 // 记忆化搜索 int dfs(int x, int y) { if (~f[x][y]) return f[x][y]; // 求最长的轨迹,最起码是1 f[x][y] = 1; for (int i = 0; i < 4; i++) { int tx = x + dx[i], ty = y + dy[i]; if (tx < 1 || tx > n || ty < 1 || ty > m) continue; if (g[x][y] > g[tx][ty]) f[x][y] = max(f[x][y], dfs(tx, ty) + 1); } return f[x][y]; } int main() { cin >> n >> m; // n行 m列 // 读入每一个点的高度 for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) cin >> g[i][j]; // 初始化-1 memset(f, -1, sizeof f); // 从每一个点出发 for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) res = max(res, dfs(i, j)); // 输出结果 printf("%d\n", res); return 0; } ```