zoukankan      html  css  js  c++  java
  • 动态规划系列题目学习

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

    什么是动态规划(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

  • 相关阅读:
    HTB-靶机-Charon
    第一篇Active Directory疑难解答概述(1)
    Outlook Web App 客户端超时设置
    【Troubleshooting Case】Exchange Server 组件状态应用排错?
    【Troubleshooting Case】Unable to delete Exchange database?
    Exchange Server 2007的即将生命周期,您的计划是?
    "the hypervisor is not running" 故障
    Exchange 2016 体系结构
    USB PE
    10 months then free? 10个月,然后自由
  • 原文地址:https://www.cnblogs.com/AmosAlbert/p/12832326.html
Copyright © 2011-2022 走看看