「SHOI2002」滑雪-动态规划

题目描述

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

然而, 当且仅当高度减小时,一个人可以从某个点滑向上下左右相邻四个点之一。

Luogu P1434

Solution

看到这道题第一眼有可能会想到线性DP,这道题用DP确实也能做,但它其实是一个标准的记忆化搜索,直接枚举从每一个点作为起点扩展时滑雪路径的长度,然后始终取最大值即可

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=110;

int dx[]={0,0,1,-1},dy[]={1,-1,0,0};//在x,y坐标上的四个方向
int a[maxn][maxn],book[maxn][maxn];
int r,c;

void read(int &x){ //输入优化
x=0;char c=getchar();
while(c<'0' || c>'9')c=getchar();
while(c>='0' && c<='9'){
x=x*10+c-'0';
c=getchar();
}
}

inline int dfs(int x,int y){ //以(x,y)为起点开始扩展
int tmp=1;
if(book[x][y]) return book[x][y];//记忆化部分,如果已经搜过了,直接返回搜出来的值
for(int i=0;i<4;i++){
if(x+dx[i]<1 || x+dx[i]>r || y+dy[i]<1 || y+dy[i]>c) continue;//边界
if(a[x+dx[i]][y+dy[i]]<a[x][y]){
tmp=max(book[x][y],dfs(x+dx[i],y+dy[i])+1);
book[x][y]=tmp;
}
}
return tmp;
}

int main(){
int ans=0;
scanf("%d%d",&r,&c);
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
read(a[i][j]);
}
}
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
ans=max(dfs(i,j),ans);//以每个点为起点扩展,最后ans为最长的那条路径
}
}
printf("%d\n",ans);
return 0;
}