zoukankan      html  css  js  c++  java
  • 记忆化搜索

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

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

    例题: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;
    }
  • 相关阅读:
    Android解析聚合数据之天气预报
    (转)微信小程序开发项目——笑话大全
    如何使用优化代码段替代WordPress插件
    通用礼品卡接口文档(KFC、必胜客、GAP等)
    TP5结合聚合数据API查询天气
    移动端开发者福利-免费收费api收藏
    【小程序】微信小程序开发实践
    一个免费的API-手机号码归属地接口
    KB错误总结
    Java 视频播放
  • 原文地址:https://www.cnblogs.com/graytido/p/10452205.html
Copyright © 2011-2022 走看看