题目:Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长底滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子
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。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。
Input
输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。
Output
输出最长区域的长度。
Sample Input
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
Sample Output
25
思路:看题目很直接可以想到用搜索,从每一个点出发,沿着4个方向找出最长下降序列,当遍历所有点之后即可得出最长的滑雪距离。但这样做n稍微大点就会超时,因为中间包含了大量的重复搜索。可以换一种思路,将每个节点的最长下降序列长度保存下来,如果待会搜索时访问到该节点,可以直接将结果返回而无需重复搜索,这种思路也被称为记忆化搜索。
代码如下:
import java.util.Scanner;
public class Main {
//滑雪问题
static int r,c,sum;//行、列、最长路径
static int map[][],dp[][];//地图数组、记忆数组
public static void main(String []args) {
@SuppressWarnings("resource")
Scanner in = new Scanner(System.in);
r = in.nextInt();c = in.nextInt();
map = newint[r][c];dp = newint[r][c];
for(inti=0;i<r;i++)
for(intj=0;j<c;j++) {
map[i][j] = in.nextInt();
dp[i][j] = -1;
}
//对问题进行初始化
for(int i=0;i<r;i++)
for(int j=0;j<c;j++)
sum = max(sum,dfs(i,j));
//对地图上的每一点进行深度搜索,并保存最大值
System.out.println(sum);
}
static int dfs(intx,inty) {
if(dp[x][y]!=-1)//如果之前已经得知了该点的最长路径,直接返回路径长度
returndp[x][y];
int t = 1;//从该点出发长度至少为1
for(int dx=-1;dx<=1;dx++) {
for(int dy=-1;dy<=1;dy++) {
if(dx!=dy&&dx+dy!=0&&(dx!=0||dy!=0))
if(inmap(x+dx,y+dy)&&map[x][y]>map[x+dx][y+dy])
t = max(t,dfs(x+dx,y+dy)+1);
//向4个方向搜索,如果下一个点在地图内并比现在所处的点低,则递归地从该点继续搜索
//当某一方向搜索完毕后,返回的长度+1即得从该点出发的路径长度
//将返回的路径长度与已保存的作比较,更新最大值
}
}
dp[x][y] = t;//当该点的4个方向都尝试过后,说明已获得从该点出发的最长路径长度,将其保存在dp数组的对应位置
return dp[x][y];//将该点的最长路径长度返回
}
static boolean inmap(intx,inty) {
return x>=0&&x<r&&y>=0&&y<c;
}//判断是否在图内
static int max(intx,inty) {
return x>y?x:y;
}//返回两数的较大值
}
代码里加入了详细的注释,如果熟悉搜索的话应该能很轻松看懂这段代码。
如果你有更好的思路欢迎在评论区留言,欢迎点赞转发,感谢阅读。