记忆化搜索

一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态。更重要的是搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多。记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来,以后再次遇到这个状态的时候,就不必重新求解了。这种方法综合了搜索和动态规划两方面的优点,因而还是很有实用价值的。记忆化搜索就相当于以搜索的形式加上动态规划的思想。

一般遇到一个动态规划类型的问题,都先要确定最优子结构,还有重叠子问题,这两个是动态规划最大的特征,然后就是要写 动态规划的状态方程,这个步骤十分十分的重要的,写动归方程是需要一定的经验的,这可以通过训练来达到目的。接着就是要自底向上的求解问题的,先将最小规模的子问题的最优解求出,一般都用一张表来记录下求得的解,到后来遇到同样的子问题的时候就可以直接查表得到答案,最后就是通过一步一步的迭代得出最后问题的答案了。
我的理解最重要的东西就是一定会要一个数组或者其他的存储结构存储得到的子问题的解。这样就可以省很多时间,也就是典型的空间换时间
动态规划的一种变形就是记忆化搜索,就是根据动归方程写出递归式,然后在函数的开头直接返回以前计算过的结果,当然这样做也需要一个存储结构记下前面计算过的结果,所以又称为记忆化搜索。

例题:pku1088滑雪

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

 

#include < algorithm >
#include < cstdio >
#include < cmath >
#include < cstring >
#include < iostream >
#include < cstdlib >
#include < set >
#include < vector >
#include < cctype >
#include < iomanip >
#include < sstream >
#include < climits >
#include < queue >
#include < stack >
using namespace std;
typedef long long ll ;
#define INF 0X3f3f3f3f
const ll MAXN = 1e3 + 7 ;
const ll MOD = 1e9 + 7 ;
int r , c ;
int mp [MAXN ][MAXN ];
int dp [MAXN ][MAXN ];
int dir [ 4 ][ 2 ] = { 0 , 1 , 0 , - 1 , 1 , 0 , - 1 , 0 };
/* 比如在这个题目中我们的dfs函数是一个倒着递归的过程,
每次的递归都能将前面的结果记录下来,这就是一个记忆化的过程 */
bool check ( int x , int y )
{
  return (x >= 1 && x <= r && y >= 1 && y <= c );
}
int dfs ( int x , int y )
{
  if (dp [x ][y ]) //记住了就不用再次dfs搜索了
  return dp [x ][y ];
  for ( int i = 0 ; i < 4 ; i ++ )
  {
    int tx = x + dir [i ][ 0 ];
    int ty = y + dir [i ][ 1 ];
    if ( check ( tx , ty ) && mp [tx ][ty ] < mp [x ][y ])
      dp [x ][y ] = max ( dfs ( tx , ty ) + 1 , dp [ x ][ y ]);
  }
  return dp [x ][y ];
}
int main ()
{
  ios::sync_with_stdio ( false );
  memset (dp , 0 , sizeof (dp ));
  cin >> r >> c ;
  for ( int i = 1 ; i <= r ; i ++ )
    for ( int j = 1 ; j <= c ; j ++ )
      cin >> mp [i ][j ];
  int ans = - 1 ;
  for ( int i = 1 ; i <= r ; i ++ )
    for ( int j = 1 ; j <= c ; j ++ )
      ans = max ( ans , dfs ( i , j ));
    cout << ans + 1 << endl ;
  // system("pause");
  return 0 ;
}

转载于:https://www.cnblogs.com/graytido/p/10452205.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值