滑雪
给定一个
R
R
R行
C
C
C列的矩阵,表示一个矩形网格滑雪场。
矩阵中第
i
i
i行第
j
j
j列的点表示滑雪场的第
i
i
i行第
j
j
j列区域的高度。一个人从滑雪场中的某个区域内出发,每次可以向上下左右任意一个方向滑动一个单位距离。当然,一个人能够滑动到某相邻区域的前提是该区域的高度低于自己目前所在区域的高度。
下面给出一个矩阵作为例子:
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
24−17−2−1
24−17−2−1。在给定矩阵中,最长的滑行轨迹为
25
−
24
−
23
−
…
−
3
−
2
−
1
25−24−23−…−3−2−1
25−24−23−…−3−2−1,沿途共经过
25
25
25个区域。
现在给定你一个二维矩阵表示滑雪场各区域的高度,请你找出在该滑雪场中能够完成的最长滑雪轨迹,并输出其长度(可经过最大区域数)。
输入格式
第一行包含两个整数
R
R
R和
C
C
C。接下来
R
R
R行,每行包含
C
C
C个整数,表示完整的二维矩阵。
输出格式
输出一个整数,表示可完成的最长滑雪长度。
数据范围
1
≤
R
,
C
≤
300
1≤R,C≤300
1≤R,C≤300
0
≤
矩阵中整数
≤
10000
0≤矩阵中整数≤10000
0≤矩阵中整数≤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
解决思路
集合状态:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]我们表示为从
i
,
j
i,j
i,j出发可以经过的路径长度。
集合划分:对于最终状态
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]的前一个状态,可以分别来自于上下左右四种情况,因此划分为
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
+
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
,
d
p
[
i
]
[
j
+
1
]
dp[i-1][j],dp[i+1][j],dp[i][j-1],dp[i][j+1]
dp[i−1][j],dp[i+1][j],dp[i][j−1],dp[i][j+1]
集合计算,我们分别遍历四种情况取最大值,但是由于我们如果采用正常的循环遍历的方式的话,得到的四种情况都是未计算的,因此我们需要使用
d
f
s
dfs
dfs先计算得到这四种情况的值,同时采用记忆化的方式进行优化。
代码实现
#include <iostream>
#include <cstring>
using namespace std;
const int N = 310;
int n, m;
int h[N][N];
int dp[N][N];
int dfs(int x, int y)
{
//剪枝
if(dp[x][y] != -1)
{
return dp[x][y];
}
//初始化
dp[x][y] = 1;
int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 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 && h[a][b] < h[x][y])
{
dp[x][y] = max(dp[x][y], dfs(a,b) + 1);
}
}
return dp[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;
memset(dp,-1,sizeof dp);
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;
}