滑雪问题(记忆化搜索)

题目: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;

   }//返回两数的较大值

}

代码里加入了详细的注释,如果熟悉搜索的话应该能很轻松看懂这段代码。

如果你有更好的思路欢迎在评论区留言,欢迎点赞转发,感谢阅读。

你可能感兴趣的:(算法)