什么是动态规划?

动态规划(Dynamic Programming)是通过组合子问题的解来解决问题的。动态规划是用于求解包含重叠子问题的最优化问题的方法。其基本思想是,将原问题分解为相似的子问题。在求解的过程中通过子问题的解求出原问题的解。

动态规划的分类:

1.       线性规划:拦截导弹,合唱队形,挖地雷等。

2.       区域规划:石子合并,加分二叉树,统计单词个数等。

3.       树形动规:贪吃的九头龙,二分查找树,聚会的欢乐等。

4.       背包问题:01背包问题,完全背包问题,分组背包问题,装箱问题,挤牛奶等

5.       除此之外还有插头DP,按位DP,状态压缩DP等等。

入门题目:数字三角形

题目描述:给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于

每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。

注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的那个数或者右边的那个数。

如:

7

3   8

8   1   0

2   7   4   4

4   5   2   6   5

分析一下为什么不能使用贪心算法,即每一次走都走下一行的两个数值较大的。因为有可能在某一步的时候数值小没走到,但是该路径下面有较大的数值,就不会走到,就得不到最大的值。

1.朴素DFS搜索算法

可以采用朴素的深度优先搜索算法,即朴素DFS。每一次走都分为两步,第一步求出走下一步时走的最大值,然后加上此步的数值。

int dfs(int x,int y) //表示从第x行,第y个数往下走可以得到的最大价值和,dfs(0,0)即为本题解。

{

       if(x > numCount - )

              return ;

       return max(dfs(x+,y),dfs(x+,y+)) + num[x][y];

}

完整的代码示例为:

#include

using namespace std;

int num[][] = {,,,,,

              ,,,,,

              ,,,,,

              ,,,,,

              ,,,,};

int numCount = ;

int dfs(int x,int y)

{

    if(x > numCount - )

       return ;

    return max(dfs(x+,y),dfs(x+,y+)) + num[x][y];

}

int main()

{

    int maxsum = ;

    maxsum = dfs(,);

    cout<<maxsum<<endl;

    return ;

}

这个算法效率极低,为什么呢?因为其中有大量的重复计算。通常递归都会有大量的重复计算。

2.DFS+记忆化搜索方法

针对于上述DFS算法的重复计算,我们可以先将dfs(x,y)的结果保存起来,等到下次需要时,直接使用。这就是记忆化搜索。

int dfs(int x,int y)

{

    if(x > numCount - )

       return ;

    if(result[x][y] != -)

       return result[x][y];

return result[x][y] = max(dfs(x+,y),dfs(x+,y+)) + num[x][y];

}

完整的代码示例为:

#include

using namespace std;

int num[][] = {,,,,,

,,,,,

,,,,,

,,,,,

,,,,};

int numCount = ;

int result[][];

int dfs(int x,int y)

{

    if(x > numCount - )

        return ;

    if(result[x][y] != -)

       return result[x][y];

    return result[x][y] = max(dfs(x+,y),dfs(x+,y+)) + num[x][y];

}

int main()

{

    for(int i = ;i < ;i++)

       for(int j = ; j < ;j++)

           result[i][j] = -;

    int maxsum = ;

    maxsum = dfs(,);

    cout<<maxsum<<endl;

    return ;

}

不论是DFS还是记忆化DFS都是基于递归的思想进行计算。总结一下实际操作的特点。
     (1)搜索的参数只有(x,y),每一对(x,y)确定一个状态。

(2)搜搜的转移是从(x+1,y)和(x+1,y+1)到(x,y)的,意思就是我们通过(x+1,y)和(x+1,y+1)的解去求(x,y)。

于是,设想:如果不用DFS,直接用数组保存状态,在状态与状态之间实现转移。

     for(int i = numCount - ; i >= ; i--)

       for(int j = ;j <= i; j++)

           result[i][j] = max(result[i+][j],result[i+][j+]) + num[i][j];

完整的程序示例为:

#include

using namespace std;

int num[][] = {,,,,,

,,,,,

,,,,,

,,,,,

,,,,};

int numCount = ;

int result[][];

int main()

{

    for(int i = ;i < ;i++)

       for(int j = ; j < ;j++)

           result[i][j] = ;

    for(int i = numCount - ; i >= ; i--)

       for(int j = ;j <= i; j++)

           result[i][j] = max(result[i+][j],result[i+][j+]) + num[i][j];

    int maxsum = ;

    maxsum = result[][];

    cout<<maxsum<<endl;

    return ;

}

总结:搜索的参数只有(x,y)。每一对(x,y)确定一个状态。我们通过(x+1,y)和(x+1,y+1)的解去求(x,y),于是我们可以设计出状态并明确状态的转移,从而写出状态转移方程。这就是动态规划!!!!

摘自:http://blog.sina.com.cn/s/blog_8eac84090102vt0y.html

作者:慕雪

从DFS到记忆化DFS到动态规划的更多相关文章

  1. poj 1088 动态规划+dfs(记忆化搜索)

    滑雪 Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u   Description Mi ...

  2. 【poj3252】 Round Numbers (数位DP+记忆化DFS)

    题目大意:给你一个区间$[l,r]$,求在该区间内有多少整数在二进制下$0$的数量$≥1$的数量.数据范围$1≤l,r≤2*10^{9}$. 第一次用记忆化dfs写数位dp,感觉神清气爽~(原谅我这个 ...

  3. HDU1978How Many Ways 记忆化dfs+dp

    /*记忆化dfs+dp dp[i][j]代表达到这个点的所有路的条数,那么所有到达终点的路的总数就是这dp[1][1]加上所有他所能到达的点的 所有路的总数 */ #include<stdio. ...

  4. 滑雪 矩阵中的最长上升路径 /// 记忆化DFS || DP oj22919

    大致题意: Description 难怪Michael喜欢滑雪,因为滑雪确实很刺激.为了获得加速度,滑雪道必须向下倾斜,而且当滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道在一 ...

  5. 【BZOJ1048】分割矩阵(记忆化搜索,动态规划)

    [BZOJ1048]分割矩阵(记忆化搜索,动态规划) 题面 BZOJ 洛谷 题解 一个很简单的\(dp\),写成记忆化搜索的形式的挺不错的. #include<iostream> #inc ...

  6. *HDU1142 最短路+记忆化dfs

    A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav ...

  7. 最大联通子数组之和(dfs,记忆化搜索,状态压缩)

    最大联通子数组,这次的题目,我采用的方法为dfs搜索,按照已经取到的数v[][],来进行搜索过程的状态转移,每次对v[][]中标记为1的所有元素依次取其相邻的未被标记为1的元素,将其标记为1,然而,这 ...

  8. HDU ACM 1078 FatMouse and Cheese 记忆化+DFS

    题意:FatMouse在一个N*N方格上找吃的,每一个点(x,y)有一些吃的,FatMouse从(0,0)的出发去找吃的.每次最多走k步,他走过的位置能够吃掉吃的.保证吃的数量在0-100.规定他仅仅 ...

  9. 洛谷 P3953 逛公园【spfa+记忆化dfs+bfs】

    spfa预处理出最短路数组dis,然后反向建边bfs出ok[u]表示u能到n点 然后发现有0环的话时候有inf解的,先dfs找0环判断即可 然后dfs,设状态f[u][v]为到u点,还可以跑最短路+v ...

随机推荐

  1. redis的常用命令01

    启动redis的命令: redis-server redis.windows.conf把redis设置成windows下的服务的命令:输入命令后刷新会出现redis的服务:redis-server - ...

  2. mycat分片操作

    mycat位于应用与数据库的中间层,可以灵活解耦应用与数据库,后端数据库可以位于不同的主机上.在mycat中将表分为两大类:对于数据量小且不需要做数据切片的表,称之为分片表:对于数据量大到单库性能,容 ...

  3. 安装PHP扩展32位与64位的误区(x86与x64的查看)

    在安装PHP扩展(DLL,SO),除了需要对应的PHP版本外,在WINDOWS还需要区分(TS线程,NTS非线程),如何判断呢? 1.如何判断是NTS还是TS(WINDOWS用户) 看PHP所在目录中 ...

  4. django ORM模型表的一对多、多对多关系、万能双下划线查询

    一.外键使用 在 MySQL 中,如果使用InnoDB引擎,则支持外键约束.(另一种常用的MyIsam引擎不支持外键) 定义外键的语法为fieldname=models.ForeignKey(to_c ...

  5. python之字符编码(二)

    一.字符编码的发展史 阶段一:现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII ASCII:一个Bytes代表一个字符(英文字符/键盘上的所有其他字符),1Bytes=8bit,8bit可以 ...

  6. grep 正则匹配

    \{0,n\}:至多n次 \{\ 匹配/etc/passwd文件中数字出现只是数字1次到3次 匹配/etc/grub2.cfg文件以一个空格开头匹配一个字符的文件的所有行 显示以LISTEN结尾的行 ...

  7. Navicat Premium 12.0.18安装与激活(转)

    转载:https://www.jianshu.com/p/42a33b0dda9c 一.Navicat Premium 12下载 Navicat Premium 12是一套数据库开发管理工具,支持连接 ...

  8. java基础篇之理解synchronized的用法

    Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this ...

  9. python使用pip下载模块

    举例下载串口模块pyserial: 下载安装了python之后,打开cmd,在python的安装目录里,搜索pip,把pip3.7.exe拖进cmd,然后输入pip3.7.exe install py ...

  10. Oracle错误——SP2-0734: 未知的命令开头 "imp C##sin..." - 忽略了剩余的行。

    错误 在windows的DOS窗口下使用命令导入Oracle数据. 原因 进入sqlplus里是不能执行imp的(sqlplus不认识imp),imp 是个工具,应该在cmd的dos命令提示符下执行.