从dfs到记忆化搜索再到动态规划

深度优先搜索之记忆化dfs 文章目录前言朴素dfs的求解思路记忆化dfs的求解思路将整数按权重排序题目描述解题思路朴素dfs记忆化dfs小结矩阵中的最长递增路径题目描述解题思路朴素dfs记忆化dfs小结统计所有可行路径题目描述解题思路朴素dfs记忆化dfs小结学生出勤记录 II题目描述朴素dfs记忆化dfs小结“马”在棋盘上的概率题目描述记忆化dfs骑士拨号器题目描述记忆化dfs记忆化dfs与棋结语 前言 前不久,我写一篇bfs的进阶版双向bfs:广度优先搜索之双向bfs 这篇文章主要是讲述对于一些特定的bfs问题,可以使用两头齐搜的 阅读详情

dfs是暴力解算,时间复杂度和空间复杂度都很废,我们可以从dfs到记忆化搜索再到动态规划优化时间复杂度,从动态规划到动态数组优化空间复杂度。

一、dp[n]

我们从一道经典的动态规划题--打家劫舍说起。

1.画出所有情况

假设这几家的现金是【50, 30, 12, 5】我们从第一家开始,可以把所有的情况画出来(打勾的表示抢劫,否则不抢)

每一家都可以选择抢劫或不抢劫。如果选了第一家,那就只能从第三家开始选;如果没有选,则可以从第二家开始选。这是每一轮递归要干的事情。

2.搞出递归关系

所以就有了这个由人话写成的函数:

//n    表示当前是第几家

//total       表示一共有几家人

int 从第n家开始拿到的钱的最大值(int n, int total)

{

        //结束条件

        如果n >= total,抢劫完毕,没法再抢劫了,返回0

        //关系式  

        从第n家开始拿到的钱的最大值 = max( 

                抢这家的钱!+ 从第n+2家开始拿到的钱的最大值 ,

                不抢这家的钱!+ 从第n+1家开始拿到的钱的最大值

        )

      返回 从第n家开始拿到的钱的最大值; 

}

转换成gcc认识的,就是:

//每一家的现金数量
//left    表示当前是第几家

//n       表示一共有几家人
int cashes[N] = {0};

int dfs(int left, int n)
{
    int temp;
    int rst = 0;
    if (left >= n)
    {
        return 0;
    }
    if (mono[left] != 0)
    {
        return mono[left];
    }
    rst = cashes[left] + dfs(left + 2, n);
    temp = cashes[left+1] + dfs(left + 3, n);
    if (temp > rst)
    {
        rst = temp;
    }
    mono[left] = rst;
    return rst;
}

3.加上记忆化搜索

在树状图中,我们很容易发现,节点12被计算了两次,如果我们能够把计算结果存其来就能极大的减少计算量。注意到函数的返回值只与参数left有关,我们就可以根据参数left来存储返回值。由于left是连续的,我们直接用数组存就好了。函数的逻辑就成了这样:

//n    表示当前是第几家

//total       表示一共有几家人

int 缓存[total] = {0};

int 从第n家开始拿到的钱的最大值(int n, int total)

{

        //结束条件

        如果缓存[n]  != 0,说明已经计算过,返回缓存[n] 

        如果n >= total,抢劫完毕,没法再抢劫了,返回0

        //关系式  

        从第n家开始拿到的钱的最大值 = max( 

                抢这家的钱!+ 从第n+2家开始拿到的钱的最大值 ,

                不抢这家的钱!+ 从第n+1家开始拿到的钱的最大值

        )

        缓存[n]  = 从第n家开始拿到的钱的最大值

      返回 从第n家开始拿到的钱的最大值; 

}

int cashes[N] = {0};
int mono[N] = {0};

int dfs(int left, int n)
{
    int temp;
    int rst = 0;
    if (left >= n)
    {
        return 0;
    }
    if (mono[left] != 0)
    {
        return mono[left];
    }
    rst = cashes[left] + dfs(left + 2, n);
    temp = cashes[left+1] + dfs(left + 3, n);
    if (temp > rst)
    {
        rst = temp;
    }
    mono[left] = rst;
    return rst;
}

4.自顶而下变自下而上(状态转移方程) 

仔细观察这个关系式

从第n家开始拿到的钱的最大值 = max( 

                抢这家的钱!+ 从第n+2家开始拿到的钱的最大值 ,

                不抢这家的钱!+ 从第n+1家开始拿到的钱的最大值

 )

我们发现“ 从第n家开始拿到的钱的最大值 ” 只和 “ 抢这家的钱!+ 从第n+2家开始拿到的钱的最大值  ”  和“  不抢这家的钱!+ 从第n+1家开始拿到的钱的最大值  ” 有关。这好像我高一刚学过的数列的递推公式。我们递归的“递”的过程是把问题分解成子问题的过程,“归”才是求解的过程。那我们为什么不直接把最小的子问题直接解决,从下往上解决问题呢?这不就省略了“递”,而直接“归”了吗?

这次,我们倒着“抢劫”,对于【50, 30, 12, 5】:

从第5家开始拿到的钱的最大值 = 5

从第4家开始拿到的钱的最大值 = max( 

                抢这家的钱!(12)+ 从第4+2家开始拿到的钱的最大值 (超出范围,0),

                不抢这家的钱!(0)   + 从第4+1=5家开始拿到的钱的最大值(5)

 ) = 12

从第3家开始拿到的钱的最大值 = max( 

                抢这家的钱!(30)+ 从第3+2=5家开始拿到的钱的最大值 (5),

                不抢这家的钱!(0)   + 从第3+1=4家开始拿到的钱的最大值(12)

 ) = 35

...以此类推,我们可以得出答案。这就是得到局部的最优解后一步一步地得到了全局的最优解。

我们可以写得装一些,这就是状态转移方程:

dp[i] = max(cashes[i] + dp[i+2], dp[i+1])

dp里面的东西其实就是我们之前写的记忆化搜索的“缓存”里面的东西。只不过这次我们不用递归得到,而是用递推。

int dp[N] = {0};

int max(int a, int b)
{
    if (a < b)
    {
        return b;
    }
    return a;
}

int s2_dp(int left, int n)
{
    dp[n] = 0;
    dp[n + 1] = 0;
    for (int i=n-1; i>=0; i--)
    {
        dp[i] = max(dp[i + 1] , dp[i + 2] + cashes[i]);
    }    
}

5.动态数组


int s3_dp(int left, int n)
{
    int i = 0, i1 = 0, i2 = 0;
    for (int j=n-1; j>=0; j--)
    {
        i = max(i1, i2 + cashes[j]);
        i2 = i1;
        i1 = i;
    }
}

6.再来一题

int min(int a, int b)
{
    if (a > b)
    {
        return b;
    }
    return a;
}

int minCostClimbingStairs(int* cost, int costSize) {
    int x = 0, x1 = 0, x2 = 0;
    for (int i=costSize-1; i>0; i--)
    {
        x = min(cost[i] + x1, cost[i] + x2);
        x2 = x1;
        x1 = x;
    }
    return min(x, x1);
}

方法都对,可是为什么报错呢?

原来迭代到i = 0的时候,x1被赋值为x,min(x, x1)就不起作用了。我们可以把i=0的特殊情况单拎出来:


int minCostClimbingStairs(int* cost, int costSize) {
    int x = 0, x1 = 0, x2 = 0;
    for (int i=costSize-1; i>0; i--)
    {
        x = min(cost[i] + x1, cost[i] + x2);
        x2 = x1;
        x1 = x;
    }
    x = min(cost[0] + x1, cost[0] + x2);
    x2 = x1;
    return min(x, x1);
}

7.再来一题

 

【2, 2, 3, 3, 3, 4】

处理一下:

              数字0的数量  数字1的数量  数字2的数量 数字3的数量 数字4的数量

数据 = 【0,                         0,                2,                 3,                         1】

 

    int dsize = 0;
    for (int i=0; i<numsSize; i++)
    {
        data[nums[i]]++;
        dsize = fmax(dsize, nums[i]);
    }

现在,每一个点都可以删除或不删除

从第n个数据开始删能得到的最大点数 = max{

        删除这个数据!(得到 “数据【n】*(n)“的点数)+ 从第n+2个数据开始删能得到的最大点数,

        不删除这个数据!(得到 0的点数)+ 从第n+1个数据开始删能得到的最大点数,

}

状态转移方程这不就来了吗?

直接无脑写上去


int deleteAndEarn(int* nums, int numsSize) {
    int dsize = 0;
    int data[10003] = {0};
    int dp[10003] = {0};
    for (int i=0; i<numsSize; i++)
    {
        data[nums[i]]++;
        dsize = fmax(dsize, nums[i]);
    }
    for (int i=dsize; i>=0; i--)
    {
        dp[i] = fmax(data[i]*i + dp[i+2], dp[i+1]);
    }
    return dp[0];
}

 注意:我一开始把这数组的初始化放到了全局区,导致没初始化为0出错。当时非常疑惑,于是把代码拷到了vscode本地运行了一下,发现是对的。所以在online judge中搞全局数组,一定要记得memset初始化一下!

(

memset 在c语言的<string.h>当中,

memset(数组, 初始化的值, 长度【以byte为单位,如果是int,就要sizeof(int)*数字个数】)

)

二、dp[i][j]

刚才函数的返回值只由一个参数决定,如果由两个参数决定呢?

那不也好办,把这两个参数都记录下来不就行了?

尝试一下

对于一个最简单的输入,我们来分析一下状态转移方程。我们给每一个点都表上坐标值(x,y),如图:

————————————

|(0,0)    |(1, 0)        |

————————————

|(0,1)   | (1,1)        |

————————————

如果我们站在(1, 0)这个点,只有一种走法,向下走。站在(0,1)这个点,也只有一种走法,向右走。如果我们站在(0, 0)这个点,如果向右走,总共有1种走法;如果向下走,总共有1种走法。加起来,(0, 0)这个点就有1+1=2种走法。

我们再分析一个稍微复杂一些的例子,结合上面的两张图,我们应该很容易得出一些规律:

设m-1 , n-1是目标点的坐标

1.从点【m-1,y】开始走,所有的走法 = 1

2.从点【x,n-1】开始走,所有的走法 = 1

3.从点【x,y】开始走,所有的走法 = 从点【x+1,y】开始走,所有的走法 + 从点【x+1,y】开始走,所有的走法

这样,很容易就能够写出状态转移方程。

再此贴出我粗拙的题解:

int uniquePaths(int m, int n) {
    long long dp[103][103] = {0};

    if (m == 1 || n==1)
    {
        return 1;
    }

    dp[m-2][n-1] = 1;
    dp[m-1][n-2] = 1;
    dp[m-1][n-1] = 1;
    
    for (int j=n-2; j>=0; j--)
    {
        dp[m-1][j] = dp[m-1][j+1];
    }
    for (int i=m-2; i>=0; i--)
    {
        dp[i][n-1] = dp[i+1][n-1];
        for (int j=n-2; j>=0; j--)
        {
            dp[i][j] = dp[i+1][j] + dp[i][j+1];
        }
    }
    return dp[0][0];
}

2.牛刀小试 

在B站上看到一位大神总结得非常到位,在这里搬运一下。这是解决动态规划题目的通法:

第一部:分析问题

第二部:分解子问题

第三部:求解最小子问题

第四步:状态转移方程

参考: 

. - 力扣(LeetCode)

动态规划(dp)入门 | 这tm才是入门动态规划的正确方式! | dfs记忆化搜索 | 全体起立!!_哔哩哔哩_bilibili

ACM 金牌选手教你动态规划的本质。力扣 No.72 编辑距离,真·动画教编程,适合语言初学者或编程新人。_哔哩哔哩_bilibili

 

数字金字塔问题(dfs、动态规划解决) 题目: 输入: 输入n,表示有n行,接下来n行,每行数如 i (1<=i<=n) 个数字。 输出: 输出为一行,输出计算结果。 输入样例 1 5 7 3 5 8 1 0 2 7 8 4 4 5 2 6 9 输出样例 1 30 方法一:搜索DFS 问题要求从最高点走到最低点的路径的最大的权值之和,起点和终点明确,可以考虑用dfs来解决。 设计好dfs函数 dfs(int x,int y,intnum) ,其中num表示坐标(1,1)到坐标(x,y)的数值最大和。. 阅读详情

相关推荐

动态规划+深度优先搜索+记忆化搜索(干货满满)

动态规划的定义 动态规划算法与分治法的思想类似,都是通过组合子问题的解来求原问题。我先来给大家介绍一下分治思想,分治思想就是把一个复杂的问题,分解为k个规模相同的子问题,如果还是无法解决,子问题又可以分为若干个相同规模的子问题求解,之后组合求原问题(难点)如二分法,归并排序,折半查找。至于动态规划:就是一个最优化问题,先将问题分解为子问题,并且对于这些分解的子问题自身就是最优的才能在这个基础上得出我们要解决的问题的最优方案(假设最优然后去求),要不然的话就能找到一个更优的解来替代这个解,得出新的最优自问题,

weixin_51335453的博客 4110

记忆化搜索

原文: http://www.cnblogs.com/fu11211129/p/4276213.html 感谢作者。 一. 动态规划 动态规划(dynamic programming),与“分治思想”有些相似,都是利用将问题分 为子问题,并通过合并子问题的解来获得整个问题的解。于“分治”的不同之处在 于,对于一个相同的子问题动态规划算法不会计算第二次,其实现原理是将每一个计算过的子问题

zark721的博客 643

一道题看懂递归、(深度搜索)dfs、记忆化搜索、动态规划(DP)的差别!

有一个层数为n(n<=1000)的数字三角形。现有一只蚂蚁从顶层开始向下走,每走下一级,可向左下方向或右下方向走。求走到底层后它所经过数字的总和的最大值。 【输入格式】 第一个整数为n,一下n行为各层的数字。 【输出格式】 一个整数,即最大值。 【输入样例 】 5 1 6 3 8 2 6 2 1 6 5 3 2 4 7 6 【输出样例】 23 【样例说明】 最大值=1+

weixin_38391092的博客 9326

动态规划5:动态规划与记忆化搜索

本期主题:动态规划与记忆化搜索

小辉的数学博客 3721

深度优先搜索(DFS)剪枝:记忆化搜索(C++)

今天我们来讲一下深搜的剪枝方法中的一个:记忆化搜索。顾名思义,记忆化搜索就是让程序记住一些东西,然后可以在需要用的时候可以瞬间调用,不需要再进行一次复杂的计算!首先,记忆需要大脑来存储数据,什么来模拟大脑? 数组其次,记忆需要现有的知识用来记住,知识从哪里来? 以前求出的数据。这样,我们如果要用到以前求过的数据,就可以从数组中调用,可以大大提高我们程序的运行速度。

小天狼星_布莱克 的博客 5257

安卓设备通过USB串口与STM32单片机通讯之一

这里写自定义目录标题欢迎使用Markdown编辑器`在这里插入代码片`新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器在这里插入代码片 你好下Markdown的基本语法知识。 新的改变 我们对

JGB联合商务组的博客 7244

递归 dfs 记忆化搜索 动态规划

今天做洛谷P1434 [SHOI2002]滑雪 的时候仔细想了想记忆化搜索 现在总结一下 为了描述问题的某一状态,必须用到该状态的上一状态,而描述上一状态,又必须用到上一状态的上一状态……这种用自已来定义自己的方法,称为递归定义。 而dfs作为一种回溯算法,是从问题的某一种可能出发, 搜索从这种情况出发所能达到的所有可能, 当这一条路走到” 尽头 “的时候, 再倒回出发点, 从另一...

weixin_30788731的博客 181

Comsol 超声空化气泡仿真

当液体中受到高能量的超声波作用时,液体中的压力会发生剧烈变化,形成局部的低压区域。当液体中的压力降低到饱和蒸汽压以下时,就会发生空化现象,即液体中形成微小气泡。这种空化常用于一些工业应用,如清洗、乳化、混合等。这种空化常用于一些医学和生物学应用,如碎石术、肿瘤治疗、细胞破碎等。超声空化的应用非常广泛。在医学领域,超声空化广泛应用于诊断和治疗,如超声造影、超声刀、超声碎石术等。在工业领域,超声空化可用于清洗、乳化、混合等工艺。此外,超声空化还在食品加工、化学合成、环境保护等领域有着重要应用。

声学黑洞仿真工作室 2555

动态规划(dfs->记忆化搜索->dp状态转移)

作为一个刚接触动态规划的蒟蒻,这几天一直在刷简单的dp题,也看了许多dp的视频,由感而发,所以诞生了这篇文章。一只会code的小金鱼的个人空间-一只会code的小金鱼个人主页-哔哩哔哩视频从up主那学到了很多东西,所以也推荐给大家,如果学习dp时,可以看看他讲的视频。同时,写该文也是让我自己记忆更加深刻一点,有一个大概的思考和总结,这很重要。

2403_88817808的博客 756

经典算法之——解决全排列问题以及详解

回溯”指的是“状态重置”,可以理解为“恢复现场”,是在编码的过程中,是为了节约空间而使用的,而在递归或者深度优先中根据需要的场合来配合回溯法可以进一步对自己的代码进行优化。, n-1, n},方向都为向左。邻位对换法是全排列生成算法中的其中一种,它的换位是双向的,通过保存数字的“方向性”来快速得到下一个排列。最后以 3 开头的全排列为[3, 1, 2], [3, 2, 1];以 1 开头的全排列为[1, 2, 3], [1, 3, 2];以 2 开头的全排列为[2, 1, 3], [2, 3, 1];

m0_68987535的博客 8794

NXP ChessDE的安装和激活

如果客户申请的是试用版,那么一份为期 30 天的 License 将会发送申请人的账号或邮箱中,客户使用该文件进行安装即可。② 将“VENDOR snpslmd /path/to/snpslmd”中的“/path/to/snpslmd”替换成 snpslmd.exe 实际存放路径(位于 SCL 安装目录下的 win32\bin 文件夹中,默认安装的情况下就是“VENDOR snpslmd C:\Synopsys\SCL\<version>\win32\bin\snpslmd.exe”)。

weixin_47351160的博客 2042

动态规划入门——记忆化搜索

动态规划之记忆化搜索,包含原理讲述已经相关代码实现。

涛涛的个人博客 5945

10分钟极速SpringBoot项目搭建:OpenClaw AI实战攻略

OpenClaw,作为一款革命性的 AI 工具,凭借其强大的智能体能力,能够在短短 10 分钟内,帮助开发者从零构建一个完整的 SpringBoot 项目,实现真正的极速开发。它不仅极大地提高了开发效率,还降低了开发门槛,让更多的开发者能够专注于业务逻辑的实现,而无需被繁琐的配置工作所困扰

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 296

(LeetCode 动态规划(基础版))70. 爬楼梯(动态规划 || 深度优先搜索dfs+记忆化)

【代码】(LeetCode 动态规划(基础版))70. 爬楼梯(动态规划 || 深度优先搜索dfs+记忆化)

记录一些刷过的题并分享学习心得 592

【DRAM存储器五十一】LPDDR5介绍--DFE与Pre-Emphasis

简述LPDDR5的DFE和预加重应用设置

highman110的博客 703

GEE案例教程:融合Sentinel-1 SAR数据、Sentinel-2光学影像和WorldPop人口数据,构建完整的洪水监测与影响评估工作流

本文介绍了一个专为巴基斯坦哈扎拉分区设计的洪水监测系统,该系统整合了Sentinel-1 SAR数据、Sentinel-2光学影像和WorldPop人口数据等多源遥感数据。系统通过VV极化SAR数据的水体提取算法(阈值-13dB)实现洪水范围监测,结合10米分辨率的光学影像进行可视化验证,并利用100米分辨率人口数据评估受灾人口。系统提供完整的技术实现,包括研究区加载、遥感数据处理、日期选择界面和洪水变化检测等功能模块,为灾害应急响应提供科学依据。

此星光明博客 191

(LeetCode 每日一题)2140. 解决智力问题(深度优先搜索dfs+记忆化 || 动态规划dp)

【代码】(LeetCode 每日一题)2140. 解决智力问题(深度优先搜索dfs+记忆化 || 动态规划dp)

记录一些刷过的题并分享学习心得 439

创新引入HAttention模块:提升YOLOv8小目标检测精度【YOLOv8】

YOLOv8在前几个版本的基础上进行了多项优化,特别是在模型的速度和精度上做了较大改进。改进的backbone:引入了更加高效的骨干网络(backbone)设计,如更深的网络层和更高效的特征提取模块。增强的Neck模块:使用了PANet等机制来更好地融合不同尺度的特征,增强了多尺度目标检测能力。增强的Head模块:包括多头检测头,以便针对不同大小的目标进行更精细的预测。尽管如此,YOLOv8仍面临着在小目标检测精度上不如大型目标的挑战,尤其在复杂背景或高密度目标环境下。

博客 2769

【LeetCode: 剑指 Offer II 099. 最小路径之和 | 暴力递归 | DFS =>记忆化搜索=>动态规划】

【LeetCode: 剑指 Offer II 099. 最小路径之和 | 暴力递归 | DFS =>记忆化搜索=>动态规划】给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:一个机器人每次只能向下或者向右移动一步。🍎作者简介:硕风和炜,优快云-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎

Coder_ljw的博客 795

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

(LeetCode 动态规划(基础版))115. 不同的子序列(动态规划dp || 深度优先搜索dfs+记忆化)

【代码】(LeetCode 动态规划(基础版))115. 不同的子序列(动态规划dp || 深度优先搜索dfs+记忆化)

记录一些刷过的题并分享学习心得 845

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

(LeetCode 热题 100)64. 最小路径和(深度优先搜索dfs + 记忆化 || 动态规划dp)

【代码】(LeetCode 热题 100)64. 最小路径和(深度优先搜索dfs + 记忆化 || 动态规划dp)

记录一些刷过的题并分享学习心得 467

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

一道题弄懂递归、深度优先搜索、记忆化搜索、DP动态规划

参考博客https://blog.youkuaiyun.com/weixin_38391092/article/details/79590710 有一个层数为n(n&lt;=1000)的数字三角形。现有一只蚂蚁从顶层开始向下走,每走下一级,可向左下方向或右下方向走。求走到底层后它所经过数字的总和的最大值。 【输入格式】 第一个整数为n,一下n行为各层的数字。 【输出格式】 一个整数,即最大值。 【输入样例 ...

little_spice的博客 2561

LCR 103. 零钱兑换 (从dfs->记忆化搜索->动态规划)

编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回。你可以认为每种硬币的数量是无限的。

weixin_67289517的博客 472

深度优先搜索DFS + 记忆化 | 动态规划:力扣337. 打家劫舍 III

1、题目描述: 2、题解: 方法1:递归,DFS 超时 最优子结构:4个孙子偷的钱+爷爷的钱 VS 两个儿子偷的钱 哪个多 # Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def rob(s

weixin_42042056的博客 285

【三角形最大路径和】递归、记忆化搜索、深度搜索(DFS打印所有路径、最大路径)、动态规划(DP)对比

参考链接,请参考原文,博主按照该文章顺了一遍,并加上自己的理解而已 下面所有的代码,如果不想提前新建nums[1000][1000],可以使用双重list动态存储 题目描述 有一个层数为n(n<=1000)的数字三角形。现有一只蚂蚁从顶层开始向下走,每走下一级,可向下或右下方向走。求走到底层后它所经过数字的总和的最大值。 【输入格式】 第一个整数为n,一下n行为各层的数字。 【输出格式】 一...

heimu24的博客 1903

【入门版动态规划(dp)】从斐波那契额数列入手,一步步解决跳台阶问题【由dfs(深度优先搜索)到记忆化搜索再到递推】

是否可以从边界出发,自底向来推。//创建一个空数组用来存储遍历过的n //这个数组的大小一定要大于你输入n的值 public static void main(String [ ] args) {//从键盘输入一个整数 memory [ 1 ] = 1;i <= n;i ++) {//这个递推公式就是dfs的向下递归公式;} }

weixin_69470199的博客 638
上一篇: 蜂鸣器奏乐
下一篇: 充电管理芯片
python_use
博客等级 码龄5年 430粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值