小谈记忆化搜索

引言

一般地,动态规划总要遍历全部的状态,而搜索可排除一些无效状态,特别是搜索可进行剪枝,减小空间开销。

如何协调动态规划的高效率与高消费间的矛盾呢?

一个折中的方法是记忆化搜索。在求解时,它依然按照自顶向下的顺序,只是每求解一个状态就将解保存,以后再遇到这种状态时,就不必重新求了。

--《算法竞赛宝典》

例题 洛谷P1434 滑雪

 

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(从24开始,在1结束)。当然25-24-23―┅―3―2―1更长。事实上,这是最长的一条。

输入的第一行为表示区域的二维数组的行数R和列数C(1≤R,C≤100)。下面是R行,每行有C个数,代表高度(两个数字之间用1个空格间隔)。

输出区域中最长滑坡的长度。

 1 /*注意:本题求的是最大的高度,即走几次再+1。*/ 
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cmath>
 6 using namespace std;
 7 int n,m,ans,zx,zy;
 8 int h[500][500];
 9 int f[500][500];
10 int dx[5]={0,0,0,1,-1};//记录上下左右走的方法,注意数组从0开始作为下标 
11 int dy[5]={0,1,-1,0,0};
12 int msearch(int i,int j);
13 int main()
14 {
15     scanf("%d%d",&n,&m);
16     for(int i=1;i<=n;i++)
17     {
18         for(int j=1;j<=m;j++)
19         {
20             scanf("%d",&h[i][j]);
21         }
22     }
23     for(int i=1;i<=n;i++)
24     {
25         for(int j=1;j<=m;j++)
26         {
27             int t=msearch(i,j);
28             ans=max(ans,t);//不断比较更长的高度 
29         }
30     }
31     printf("%d",ans);
32     return 0;
33 }
34 int msearch(int i,int j)
35 {
36     int t=1;
37     if(f[i][j]>0) return f[i][j];//记忆化搜索的关键之1 
38     for(int k=1;k<=4;k++)
39     {
40         zx=i+dx[k];
41         zy=j+dy[k];
42         if(h[zx][zy]>h[i][j]&&zx>=1&&zx<=n&&zy>=1&&zy<=m)//是否满足条件&数组防越界 
43          t=max(msearch(zx,zy)+1,t);//t先前设成1了(起始高度为1) 
44     }
45     f[i][j]=t;//记忆化搜索关键之2,都搜完后记录。 
46     return t;
47 }

 昨日小测中的题目略微有所改动。

题目如下:

香穗子在田野上调蘑菇!她跳啊跳,发现自己很无聊,于是她想了一个有趣的事情,每个格子最多只能经过1次,且每个格子都有其价值

跳的规则是这样的,香穗子可以向上下左右四个方向跳到相邻的格子,并且她只能往价值更高(这里是严格的大于)的格子跳.

香穗子可以从任意的格子出发,在任意的格子结束,

那么她最多能跳几次?

本质也是记忆化搜索。另外需注意两点。

1.问的是跳几次,不同于求高度,最后需-1;

2.“每个格子最多只能通过1次”不需另做处理。

posted @ 2018-03-17 12:55  cellur925&Chemist  阅读(148)  评论(0编辑  收藏  举报