记忆化搜索

这应该是我第二次学记忆化搜索之前学过一次,但是好像什么都没学到
先来个例题
记忆化搜索,所谓记忆化搜索,就是在普通搜索的基础上增加记录,记录下每一步的最优解法,一般用于求最大值之类。在每步都记录下数值,最后函数数值即为解。

是dp的一种实现形式:一种递归的写法,递归求解每一种状态

其实每一个动态规划的问题都可以用递归的方式写,而且递归的方式回更加容易理解一些,

状态表示是两维,因为是个矩阵嘛
f[i, j]就是所有从(i, j)开始滑的路径
状态计算:按照第一步是往哪边滑的把情况分为四类
向左向右向上向下,然后以向右为例,就是从f[i, j]到f[i, j+1]然后寻找从f[i, j +1]到终点的最长距离,其实就是f[i, j+1]+1,这四类情况并不一定都存在,需要判断一下,把存在的取个遍,找个max就行

而且要求这个图是拓扑图,不能存在环 ,因为如果存在环的话,就会一直递归,谁也求不出来谁
不过本题不存在环

我们要递归地算每一个状态,一般是这么一个套路,我们先把所有的状态初始化成-1,代表每个状态都没有被算过

记忆化搜索_第1张图片

int &v = f[x][y]这是C++里面的一个技巧,每个写v的地方就相当于写 f[x][y]
枚举上下左右四个方向的话,用偏移量int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

#include 
#include 
#include 

using namespace std;

const int N = 310;

int n, m;
int g[N][N];
int f[N][N];

int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

int dp(int x, int y)
{
    int &v = f[x][y];
    if (v != -1) return v;

    v = 1;//最小值就是1,也就是就当前这个点 
    for (int i = 0; i < 4; i ++ )
    {
        int a = x + dx[i], b = y + dy[i];
        if (a >= 1 && a <= n && b >= 1 && b <= m && g[x][y] > g[a][b])
            v = max(v, dp(a, b) + 1);
    }

    return v;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            scanf("%d", &g[i][j]);

    memset(f, -1, sizeof f);

    int res = 0;
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            res = max(res, dp(i, j));

    printf("%d\n", res);

    return 0;
}

优点:我们经常关注的就是时间复杂度和空间复杂度
但是考试的时候还要关注代码复杂度:也就是我们想出来的这个算法好不好写,就是我们这个算法思路给出来是不是很麻烦,一般代码复杂度最重要
虽然看着代码长一些,但是思路很简单,错了很容易调试,只要把状态转移方程写出来就可以直接实现

但是循环的话,就很难
缺点:比循环满,递归过多容易爆栈

你可能感兴趣的:(dp,算法,算法,动态规划,c++)