• 动态规划系列题目学习


    “如果你想的算法是正确的,那么它一定能够被证明,不然就是直觉”

    什么是动态规划(DP)

    谈起动态规划(DP),我们首先要了解什么是DP

    动态规划的一个思想就是,用空间换时间,既然我在转移的过程中,把某个点(i,j)的dp(i,j)给求了出来,那么为了避免下次其他点转移到这个点又要重复工作,干脆就把已经求出来的dp(i,j)的值记录下来,那么下次再遇到的时候,直接查表。这样,可以保证每个点(i,j)都只求一次dp(i,j)。

    因此动态规划又叫做填表法,就是说动态规划就是个填表游戏。
    我认为动态规划 可以理解为记忆化搜索

    可以参考
    1、自底向上:思想是逆向的,但也能正向解答。两者是相同的,只是求解顺序不一样。
    2、状态转移方程:对于这个,我只能说,暴力怎么解,动态规划就怎么解。因为求解动态规划的顺序是先暴力递归——带备忘录的递归(即先记录一些已经求出来的值,没必要每次都重新求)——动态规划。并且看博客多了的人会发现,其实递归的递归体就是动态规划的状态转移方程。不同的思考,得出的状态转移方程也不一样。
    3、最优子问题:大问题分成小问题,小问题寻找最优解构成大问题的最优解。这一点不必太在意,因为求解的过程就是在求解小问题的最优解。

    上面这些话,我已经听过加看过几十遍了,可是见到动态规划系列的题目还是要么没思路,要么直接暴力,重新学习记录一下
    最后学习动态规划,光靠理论是不行的,得结合实战

    动态规划题目的特点

    1.计数:
    有多少种方式走到右下角
    有多少种方法选出k个数使得和是Sum

    2.求最大最小值
    从左上角走到右下角路径的最大数字和
    最长上升序列长度

    3.求存在性
    取石子游戏,先手是否必胜,求存在性
    能不能选出k个数使得和是Sum

    例1

    你有三种硬币,分别面值2元,5元,7元,每种硬币足够多 买一本书27元 ,如何用最少的硬币组合正好付清,不需要对方找钱

    最少揭示了可以使用DP

    DP组成部分 1

    确定状态

    状态是什么?
    状态在动态规划中的作用属于定海神针

    简单的说,解动态规划的是否需要开一个数组,数组的每个元素f[i]或者f[i][j]代表什么
    类似于数学方程中的的x,y,z代表什么。

    确定状态需要两个意识
    :最后一步

    在这里插入图片描述
    ak最优,27-ak也要最优

    :子问题转变成
    

    在这里插入图片描述

    · 等等,我们还不知道最后那枚硬币ak是多少
    · 最后那枚硬币ak只可能是2,5或者7
    · 如果ak是2,f(27)应该是f(27-2)+1(加上最后这一枚硬币2)
    · 如果ak是5,f(27)应该是(27-5)+1(加上最后这一枚硬币5)
    · 如果ak是7,f(27)应该是f(27-7)+1(加上最后这一枚硬币7)
    · 除此以外,没有其他的可能了

    在这里插入图片描述

    硬币这道题递归也可以解

    核心代码如下:

    
    int f(int x)
    {                                  //f(x)=最少用多少枚硬币拼出x 
    	if(x==0)
    	{
    		return 0;                 //0元只需要0枚硬币 
    	}
    	int res = MAX_VALUE;           //初始化用无穷大 
    	if(x>=2)                                      //最后一枚硬币是2元 
    	{
    		res=Math.min(f(x-1) + 1,res);
    	}
    	if(x>=5)                                                            //最后一枚硬币是5元 
    	{
    		res=Math.min(f(x-1) + 1,res);
    	}
    	if(x>=7)                                                                                 //最后一枚硬币是7元 
    	{
    		res= Math.min(f(x-7)+1,res);
    	}
    	return res;
     } 
    

    但是递归过程中会计算大量重复计算过的值,它并不会记忆,因此很可能造成超时问题。

    DP组成部分 2 转移方程

    设状态f【x】=最少用多少枚硬币拼出x

    对于任意的x,
    在这里插入图片描述

    DP组成部分 3 初始条件和边界情况

    ·f[X]=min{f[X-2]+1,f[X-5]+1,f[X-7]+1}
    ·两个问题:X-2,X-5或者X-7小于0怎么办?什么时候停下来?
    ·如果不能拼出Y,就定义f[Y]=正无穷
    -例如f[-1]=f[-2]…=正无穷
    ·所以f[1]=min(f[-1]+1,f[-4]+1,f[-6]+1}=正无穷,表示拼不出来1。。。正无穷加1还是正无穷

    初始条件:

    f[0]=0;有些题目会定义多个f[0],f[1]… 初始条件就是用转移方程算不出来,但需要手动定义。很多题目都是初始条件f[0]=0,这道题也是。

    边界情况:

    不要数组越界(下或上)

    DP组成部分 4 计算顺序

    大多数一维从小到大,大多数二维就会从左到右,从上到下

    初始条件:f[0]=0
    然后计算f[1],f[2],…f[27]

    确定顺序方法:当我们计算到f[x]时,f[x-2],f[x-5],f[x-7]都已经得到结果了,因此需要用循环来保证

    每一步尝试三种硬币,一共27步

    与递归算法相比,没有任何重复计算

    算法时间复杂度(即需要进行的步数):27 * 3

  • 相关阅读:
    RocketMQ(十):数据存储模型的设计与实现
    常用sql语句
    配色方案
    WPF界面MahApps.Metro之应用
    使用 Zendesk maxwell 对接 kinesis (include producer and consumer)
    oracle报错【ORA-01017:用户名/口令无效;登录被拒绝】问题处理
    oracle报错【ORA-28000:帐户已被锁定】问题处理
    $(window).load(function(){})和$(document).ready(function(){})的区别
    HttpClientFactory 结合 Polly 轻松实现重试机制
    ocelot 中间件的变化
  • 原文地址:https://www.cnblogs.com/AmosAlbert/p/12832326.html
Copyright © 2020-2023  润新知