给定一个 R R R行 C C C列的矩阵,表示一个矩形网格滑雪场。
矩阵中第 i i i 行第 j j j 列的点表示滑雪场的第 i i i 行第 j j j 列区域的高度。
一个人从滑雪场中的某个区域内出发,每次可以向上下左右任意一个方向滑动一个单位距离。
当然,一个人能够滑动到某相邻区域的前提是该区域的高度低于自己目前所在区域的高度。
下面给出一个矩阵作为例子:
在给定矩阵中,一条可行的滑行轨迹为24-17-2-1
。
在给定矩阵中,最长的滑行轨迹为25-24-23-…-3-2-1
,沿途共经过
25
25
25个区域。
现在给定你一个二维矩阵表示滑雪场各区域的高度,请你找出在该滑雪场中能够完成的最长滑雪轨迹,并输出其长度(可经过最大区域数)。
输入格式
第一行包含两个整数
R
R
R和
C
C
C。
接下来
R
R
R行,每行包含
C
C
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
数据范围
1 ≤ R , C ≤ 300 1≤R,C≤300 1≤R,C≤300, 0 ≤ 0≤ 0≤矩阵中整数 ≤ 10000 ≤10000 ≤10000
算法思想(记忆化搜索)
根据题目描述,可以从矩阵中任意一个位置作为起点,通过DFS计算其所能完成的最大滑雪长度,求出其中的最大值即可。
在DFS过程中,可以记录每个点所能达到的最大滑雪长度,避免重复计算,这种实现搜索的方式就是记忆化搜索。在搜索过程中,对于已经计算过的状态,直接返回结果;否则,进行搜索并将计算结果记录下来。
本题中,使用f[x][y]
记录从位置
(
x
,
y
)
(x,y)
(x,y)出发,所能完成的最大滑雪长度。DFS搜索顺序如下:
- 如果
f[x][y]
的值不为0,说明已搜索过,直接返回结果。 - 将
f[x][y] = 1
,表示从 ( x , y ) (x,y) (x,y)出发可以滑动一个单位距离。 - 从 ( x , y ) (x,y) (x,y)向上下左右任意一个方向进行扩展,扩展一个合法位置 ( a , b ) (a,b) (a,b)
- 从
(
a
,
b
)
(a,b)
(a,b)继续递归搜索,同时将搜索过程中的最大值保存到
f[x][y]
- 最终返回
f[x][y]
代码实现
#include <iostream>
using namespace std;
const int N = 310;
int f[N][N], h[N][N];
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
int n, m;
//DFS计算从(x,y)点出发的最长滑雪轨迹
int dfs(int x, int y){
//从(x,y)点出发的最长滑雪轨迹已经计算过,直接返回
if(f[x][y]) return f[x][y];
f[x][y] = 1; //初始状态,至少滑过一个点
//向四个方向扩展,计算下一步的最大值
for(int i = 0; i < 4; i++)
{
int a = x + dx[i], b = y + dy[i];
//越界检查
if(a < 1 || a > n || b < 1 || b > m) continue;
//可行性剪枝
if(h[a][b] >= h[x][y]) continue;
f[x][y] = max(f[x][y], dfs(a, b) + 1);
}
return f[x][y];
}
int main()
{
cin>>n>>m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin>>h[i][j];
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;
}