什么是动态规划?

动态规划(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. django框架基本介绍

    一.mvc和mtv 1.mvc介绍 MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器( ...

  2. mxnet下如何查看中间结果

    https://blog.csdn.net/disen10/article/details/79376631 固定权重:https://www.cnblogs.com/chenyliang/p/678 ...

  3. log4j2笔记 #03# PatternLayout

    该类的目标是格式化LogEvent并返回(字符串)结果.结果的格式取决于具体的模式字符串(pattern string).这里的模式字符串与c语言中printf函数的转换模式非常相似.模式字符串由“转 ...

  4. MySQL字符类型datetime与timestamp

    这片博客来详细分区一下这哥俩! 首先来说明这两个字符类型: DATETIME 8 1000-01-01 00:00:00 ~9999~12-31 23:59:59 0000-00-00 00:00:0 ...

  5. JDK源码之ReentrantLock

    1.定义 ReentrantLock是一种可重入锁,允许一个线程对同一个资源重复加锁,如果说是当一个线程调用一个锁的lock()方法,然后再次调用锁的lock()方法,当锁不支持可重入时,该线程会被自 ...

  6. cannot_delete_plugins_expand_dir "/var/lib/rabbitmq/mnesia/rabbit@iZbp1iiexwyqe7tpjigcg9Z-plugins-expand"

    [root@iZbp1iiexwyqe7tpjigcg9Z rabbitmq]# cat startup_err /usr/lib/rabbitmq/bin/rabbitmq-env: line 91 ...

  7. ldap集成x-pack

    ldap配置支持x-pack有两种格式: 1.  User Search Mode 2. User DN Templates Mode 由于第一种方式需要明文填入ldap管理员账号信息,我这边采用第二 ...

  8. 存根类(stub) 是什么意思?有什么作用?(转)

    存根类是一个类,它实现了一个接口,但是实现后的每个方法都是空的.  它的作用是:如果一个接口有很多方法,如果要实现这个接口,就要实现所有的方法.但是一个类从业务来说,可能只需要其中一两个方法.   如 ...

  9. centos7之安装wordpress

    wordpress安装教程如下: mysql安装可以参考我的博客园Centos构建Java环境:https://www.cnblogs.com/youcong/p/9118753.html 1.安装a ...

  10. Django创建超级用户出现错误

    如果运行python manage.py createsuperuser出现一大堆错误代码 解决方案: 1.检查settings.py中的DATABASE配置确定正确性 2.执行python mana ...