dp-动态规划问题浅析

动态规划题目特点:

1、计数

有多少种方式走到右下角

有多少种方法选出k个数使得和是sum

2、求最大最小值

从左上角走到右下角路径的最大数字和

最长上升子序列长度

3、求存在性

取石子游戏,先手是否必胜

能不能选出k个数使得和是sum

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

动态规划组成部分一:确定状态

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

简单的说,解动态规划的时候需要开一个数组,数组的每个元素f[i]或者f[i][j]代表什么

类似于解数学题中,x,y,z代表什么

确定状态需要两个意识:

最后一步

子问题

最后一步:

虽然我们不知道最有策略是什么,但是最优策略肯定是k枚硬币a1,a2,…ak面值加起来是27

所以一定有一枚最后的硬币:ak

除掉这枚硬币,前面的硬币的面值加起来是27-ak

关键点1

我们不关心前面的k-1枚硬币是怎么拼出来27-ak的,而且我们现在甚至不知道ak和k,但是我们确定了前面的硬币拼出了27-ak

关键点2

因为是最优策略,所以频出27-ak的硬币数一定要最少,都则这不是最优策略了

子问题

所以我们要求:最少用多少枚硬币可以拼出27-ak

原问题是最少用多少枚硬币拼出27

我们将原问题转化成一个子问题,而且规模更小:27-ak

为了简化定义,我们设状态f(X)=最少用多少枚硬币拼出X

递归解法

int f(int x){
    if (x==0) return 0;
        int res = MAX_VALUE;
    if(x>=2)
        res = Math.min(f(x-2)+1,res);
    if(x>=5)
        res = Math.min(f(x-5)+1,res);
    if(x>=7)
        res = Math.min(f(x-7)+1,res);
    return res;
}

但是递归效率低下,做了很多重复的工作

 

动态规划组成部分二:转移方程

 

 

动态规划组成部分三:初始条件和边界情况

 

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

初始条件f[0]=0;

 

 

动态规划组成部分四:计算顺序

 

拼出x所需要的最少硬币数:f[x] = min{f[x-2]+1,f[x+5]+1,f[x-7]+1}

初始条件:f[0]=0

然后计算f[1],f[2],…,f[27]

当我们计算到f[x]时,f[x-2],f[x-5],f[x-7]都已经得到结果了

 

 

求最值型动态规划

动态规划组成部分:

一、确定状态

最后一步(最优策略中使用的最后一枚硬币ak

化成子问题(最少的硬币拼出更小的面值27-ak)

二、转移方程

f[x] = min{f[x-2]+1,f[x-5]+1,f[x-7]+1}

三、初始条件和边界情况

f[0]=0,如果不能拼出Y,f[Y]=正无穷

四、计算顺序

f[0],f[1],f[2],…

消除冗余,加速计算

 

问题二:

给定一个m行n列的网格,有一个机器人从左上角(0,0)出发,每一步可以向下或者向右走一步

问有多少种不同的方式走到右下角

0,0

0,1

0,2

0,3

0,4

0,5

0,6

0,7

1,0

1,1

1,2

1,3

1,4

1,5

1,6

1,7

2,0

2,1

2,2

2,3

2,4

2,5

2,6

2,7

3,0

3,1

3,2

3,3

3,4

3,5

3,6

3,7

 

(计数型动态规划)

 

动态规划组成部分一:确定状态

最后一步:无论机器人用何种方式到达右下角,总有最后挪动的一步:

向右或者向下

右下角坐标为(m-1,n-1)

那么前一步机器人一定是在(m-2,n-1)或者(m-1,n-2)

 

子问题

那么,如果机器人有x种方式从左上角走到(m-2,n-1),有Y种方式从左上角走到(m-1,n-2),则机器人有(X+Y)种方式走到(m-1,n-1)

问题转化为,机器人有多少种方式从左上角走到(m-2,n-1)和(m-1,n-2)

原问题要求有多少种方式从左上角走到(m-1,n-1)

子问题

状态:设f[i][j]为机器人有多少种方式从左上角走到(i,j)

动态规划组成部分二:转移方程

对于任意一个格子(i,j)

f[i][j]=f[i-1][j]+f[i][j-1]

动态规划组成部分三:初始条件和边界情况

初始条件:f[0][0] = 1,因为机器人只有一种方式到左上角

边界情况:i=0或j=0,则前一步只能有一个方向过来->f[i][j]=1

动态规划组成部分:计算顺序

f[0][0] = 1

计算第0行:f[0][0],f[0][1],…,f[0][n-1]

计算第1行:f[1][0],f[1][1],…,f[1][n-1]

计算第m-1行:f[m-1][0],f[m-1][1],…,f[m-1][n-1]

 

内容参考自:【动态规划专题班】ACM总冠军、清华+斯坦福大神带你入门动态规划算法_哔哩哔哩_bilibili

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
打家劫舍是一个经典的动态规划问题。根据引用\[2\]中的解法,我们可以使用动态规划来解决这个问题。假设偷窃房屋的下标范围是\[start, end\],用dp\[i\]表示在下标范围\[start, i\]内可以偷窃到的最高总金额。根据状态转移方程dp\[i\] = max(dp\[i − 2\] + nums\[i\], dp\[i − 1\]),我们可以通过递推得到最终的结果。 在解决这个问题时,我们可以使用滚动数组来降低空间复杂度,只需要存储前两间房屋的最高总金额,将空间复杂度降到O(1)。具体的代码实现可以参考引用\[2\]中的代码。 另外,对于打家劫舍 III这个问题,根据引用\[3\]中的解法,我们可以使用递归的方式来解决。对于每个节点,我们可以选择偷取该节点的钱和其四个孙子节点的钱,或者选择偷取其两个儿子节点的钱,然后比较两种方案的钱数,选择钱数较多的方案作为当前节点能偷取的最大钱数。 具体的代码实现可以参考引用\[3\]中的代码。 综上所述,我们可以使用动态规划来解决打家劫舍问题,具体的解法可以参考引用\[2\]中的代码。对于打家劫舍 III这个问题,可以使用递归的方式来解决,具体的解法可以参考引用\[3\]中的代码。 #### 引用[.reference_title] - *1* *2* *3* [动态规划解决打家劫舍问题](https://blog.csdn.net/p1967914901/article/details/125372599)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值