前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >数据结构之动态规划问题

数据结构之动态规划问题

作者头像
小小詹同学
发布于 2019-05-13 08:24:31
发布于 2019-05-13 08:24:31
57800
代码可运行
举报
文章被收录于专栏:小詹同学小詹同学
运行总次数:0
代码可运行

数据结构中动态规划应该算得上是你避不开的一道槛了吧!其重要性不言而喻,今天就整理下学习笔记分享出来。希望对读者朋友也能有帮助,文章基本框架如下:

  • 什么是动态规划
  • 小偷的背包问题
  • LeetCode刷题

什么是动态规划

定义

动态规划(英语:Dynamic programming,简称DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。

上述是维基百科的解释。能够看的出来最为关键的点有这样3个。

  • 最优子结构
  • 最小子问题边界
  • 状态转移函数(拆分转化方法) 最优子结构指的是某一阶段复杂问题可以拆解成之前某些阶段的子问题;边界则是指对于最小子问题的解;状态转移方法指的是复杂某阶段复杂问题和之前阶段的转化关系。

举例解释

我们可以以斐波那契数列(Fibonacci)为例!

1, 1, 2, 3, 5, 8, 13 ,21 …

如果把第n个斐波拉契数记作 F(n),那么怎样利用动态规划来解释这个问题呢?

先谈最小子问题边界,当然是最前边的两个数F(1)和F(2)。

F(1)=F(2)=1。

最优子结构则是当前阶段斐波拉契数可以由之前斐波拉契数计算而出,计算关系则是我们说的状态转移方法。这里的状态转移函数为:

F(n)=F(n-1)+F(n-2),n>2

小偷的背包问题

上述斐波拉契数的例子只是用来举例便于理解动态规划的3个特点。真正经典的动态规划题目是小偷的背包问题:

一个小偷闯进一家珠宝店,他只背了一个可承重W的背包,珠宝店里有N件物品,其重量分别为w1,w2……wN,其价值分别为v1,v2……vN。那么问题来了,小偷该选择偷哪些东西用背包带走呢?(假设都为整数单位)

用动态规划的思路来解决这个题目,可以把物品的种类和书包承重力当成状态,绘制出一个二维表格如下,行表示种类从1到N,列表示承重从0到W。

0

1

……

W

1

2

……

N

再定义2个列表存储N类物品各自的重量和价值:

w=[w1,w2,……wN] v=[v1,v2,^vN]

先思考整体过程

首先假设只有一件物品重量w[0]价值v[0],假设背包承重能力从0到W,被偷的最大价值为res,也就是第一行从左到右的过程。

不难想象,这时只用判断背包承重是否能够承受第一行对应物品,不能则res=0,能则被偷走,res=v[0]。

0

1

……

W

1

0

v[0]

……

v[0]

2

……

N

确定第一行(边界)不难,关键在于如何找到状态转移函数,即res[i][j]是如何从之前状态获取计算的。res[i][j]表示共i+1件物品,j承重的时候,能偷走的最大价值。(加1是因为列表索引从0开始)

选择边界并确定状态转移函数

重点来了!当已知res[i-1][:]所有状态,现在有第i+1件物品可以选择,我们该怎么判断?

首先判断第i+1件物品是否超出背包当前承重(即w[i]>j),超出则肯定放不进去,最大价值和有无第i+1件物品无关,即res[i][j]=res[i-1][j]。

当可以放进去的时候,有两个选择,放或不放,选择不放该物品,则依旧是res[i][j]=res[i-1][j];选择放该物体则最大价值是res[i][j]=v[i]+res[i-1][j-w[i]],表示放了之后剩余载重可带走的最大价值。

两种选择取其大者即可!上述逻辑代码如下,也是核心代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for i in range(1,N):#从第二行开始
    for j in range(C+1):
        #这里是关键的状态转移函数
        if j < w[i]:
            res[i][j] = res[i-1][j]
        else:
            res[i][j] = max(res[i-1][j], v[i]+res[i-1][j-w[i]])#注意这里,应当设置承重为0的情况(即j从0C+1);可能存在j=w[i]

return res

当返回了res后,其实res[N-1][C]即为所求的最大价值。

但是!如果我要你告诉我你选择哪几件物品的时候能取得上述最大值呢?思考一分钟再往后看!

其实,这会我们反过来看就比较简单了,因为上述核心就是对比res[i][j]和res[i-1][j],能够想到如果二者不相等的时候,必然说明res[i][j]对应的物品偷走了(没偷走二者应当相等),若取走了该件物品,背包载重则减少了对应的承重。所以这样就能够判断出小偷偷走的是那些物品了,需要注意的是当i=1的时候无法判断res[0][j]对应行是否偷走,这里应当利用剩余承重是否为0了。

有点绕口,基本上是逐行把自己代码的思路讲解出来的,而不是直接给代码,希望对小白友好些。

代码实现

talk is cheap,show me the code:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# Author:小詹
#Date:2019-4-18
#动态规划的背包类问题,Python实现

def bag(N,C,w,v):
    '''
    N:物品种类
    C:背包承重
    w:物品种类对应的重量,列表
    v:物品种类对应的价值,列表
    '''
    res = [[0 for j in range(C+1)] for i in range(N)] #全0表格,1-N件物品,0-C承重

    for j in range(C+1):#初始化第一行边界
        if j < w[0]:
            res[0][j] = 0
        else:
            res[0][j] = v[0]
#     print(res)

    for i in range(1,N):#从第二行开始
        for j in range(C+1):
            #这里是关键的状态转移函数
            if j < w[i]:
                res[i][j] = res[i-1][j]
            else:
                res[i][j] = max(res[i-1][j], v[i]+res[i-1][j-w[i]])#注意这里,应当设置承重为0的情况(即j从0C+1);可能存在j=w[i]

    return res

def show(N,C,w,res):
    '''
    通过比较res[i][j]和res[i-1][j]是否相等判断是否装了第i+1件物品;
    小詹这里没有充分发挥列表下标从0开始的特点,导致要做+1操作,能理解就好
    '''
    print('背包能放下物体最大价值为:',res[N-1][C])
    print(res)

    j = C
    pick = []

    for i in range(N-1,0,-1):
#         print(i)
        if res[i][j] > res[i-1][j]:
        #因为res中从0开始是第1行,这里i-1对应第i行;将第i行和i-1行对比,如果不一样则表示背包装了第i行对应的物品
            pick.append(i+1)
            j-=w[i-1]               
    if j > 0:
        pick.append(1)

    print('背包依次装了第',pick,'件物品')

def main():
    N = 5
    C = 10
    w = [2, 2, 6, 5, 4]
    v = [6, 3, 5, 4, 6]

    res = bag(N,C,w,v)
    show(N,C,w,res)

if __name__ =='__main__':
    main()    

上述就是完整代码。(码字不易,转用请注明出处)

LeetCode刷题

嗯哼,如果你把前两部分彻底搞懂了,对动态规划至少也算是有个初步了解了吧!

熟能生巧,当然得在力扣上找点题目练练手吧?这里有3道题可以去尝试一下噢!

1.LeetCode第5题————最长回文字串 2.LeetCode第10题————正则表达式匹配 3.LeetCode第32题————最长有效括号 4.Leetcode第62题————不同路径 5.Leetcode第63题————不同路径2

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-04-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小詹学Python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
掌握套路,你也会用动态规划
动态规划并不是一种具体的算法,而是一种思想,个人觉得就是缓存+枚举,把求解的问题分成许多阶段或者多个子问题,然后按顺序求解各子问题。前一子问题的解为后一子问题提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
Java识堂
2020/07/13
4640
Python 刷题笔记:背包问题
刷动态规划的第二天,有些自闭,刚靠着大魔王的歌缓过来了。关于动态规划,我还处于看题解时哦哦哦、看题目时???的阶段,所以整理的点不深。除了昨天推给大家的链接,今天也是发现了一位刷题大牛的宝藏,不仅动态规划,各类算法都做了整理、引导,属实 respect !
TTTEED
2020/07/08
7980
【动态规划/背包问题】那就从 0-1 背包问题开始讲起吧 ...
如果你还没看过,我十分建议你抽时间去学习一下。因为 路径问题 里教到的「经验解法」和「技巧解法」将会贯穿我们之后的所有「动态规划专题」系列。
宫水三叶的刷题日记
2021/04/08
1K0
算法细节系列(9):动态规划之01背包
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014688145/article/details/70175161
用户1147447
2019/05/26
4370
动态规划--0,1背包问题(再也不怕类似背包问题了)
这种类型问题三大要素:总重量、每件物品重量、每件物品价值,问最终能够塞进背包中的价值最大是多少?应该怎么选择物品?
西西嘛呦
2020/08/26
4550
算法:动态规划
上面是一个按照时间段发生的任务a,b,c,d,e,f,g,h,有的任务之间会有时间重叠。定义:
用户3578099
2022/04/18
1.7K0
算法:动态规划
【算法学习】动态规划
动态规划(dynamic programming)是一种基础的算法设计思想。作为一种寻找最优解的通用方法,它是在20世纪50年代由美国数学家Richard Bellman(也就是之前最短路径问题中Bellman ford算法的发明者之一)所发明的。
短短的路走走停停
2019/11/10
7140
【算法学习】动态规划
八十八、从斐波那契数列和零一背包问题探究动态规划
本人看了vivo,阿里巴巴的校招算法题,可以明确知道绝对有动态规划。如果没有,那么出题的面试官真的没有水平。跌了N次的动态规划,Runsen最近也拼命搞动态规划。这篇文章浪费了三天时间。
润森
2022/08/17
4360
八十八、从斐波那契数列和零一背包问题探究动态规划
动态规划解决01背包问题
一、问题描述:有n 个物品,它们有各自的重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
Christal_R
2019/09/11
8350
【蓝桥杯2022省赛】备赛蓝桥杯经典动态规划。背包问题、背包与魔法、李白打酒加强版
给你一个可装载重量为 W 的背包和 N 个物品,每个物品有重量和价值两个属性。其中第 i 个物品的重量为 w[i],价值为 v[i],现在让你用这个背包装物品,最多能装的价值是多少?
小小程序员
2023/02/08
4930
动态规划 入门
动态规划(英语:Dynamic programming,简称DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题[1]和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。 动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再根据子问题的解以得出原问题的解。
MashiroT
2023/01/18
4110
最详细动态规划解析——背包问题
要解决一个复杂的问题,可以考虑先解决其子问题。这便是典型的递归思想,比如最著名的斐波那契数列,讲递归必举的例子。
全栈程序员站长
2022/09/19
3310
最详细动态规划解析——背包问题
动态规划解决背包问题
1.动态规划 算法的核心思想是:将大问题划分成小问题进行解决,从而一步步获取最优解的处理算法
暴躁的程序猿
2022/03/24
3280
动态规划解决背包问题
总结——01背包问题 (动态规划算法)
0-1 背包问题:给定 n 种物品和一个容量为 C 的背包,物品 i 的重量是 wi,其价值为 vi 。
全栈程序员站长
2022/09/17
5560
0-1背包问题的动态规划法与回溯法
例:0-1背包问题。在使用动态规划算法求解0-1背包问题时,使用二维数组m[i][j]存储背包剩余容量为j,可选物品为i、i+1、……、n时0-1背包问题的最优值。绘制
全栈程序员站长
2022/09/06
5170
0-1背包问题的动态规划法与回溯法
巧解动态规划问题
前言:最近在力扣刷题,但是之前从没有接触过算法题,有的看答案都看不懂,后来做的题做多了发现有好多类似的题目,所以我打算总结一下规律。
wsuo
2020/07/31
7700
巧解动态规划问题
01-背包问题及相关应用
有 N 件物品和一个容量为 C 的背包。第 i 件物品的重量是 w[i],价值是 v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。如:
echobingo
2019/06/11
6680
01-背包问题及相关应用
九十、动态规划系列背包问题之多重背包
题目是这样的:来源:https://www.acwing.com/problem/content/4/
润森
2022/08/17
5620
九十、动态规划系列背包问题之多重背包
动态规划之背包问题(C语言)
动态规划(英语:Dynamic programming,简称DP)是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题 动态规划思想大致上为:若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 由于通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。
全栈程序员站长
2022/09/14
8840
动态规划之背包问题(C语言)
动态规划--重拾我的“背包”
  背包问题所涉及的是经典的动态规划算法。因为长时间不AC了,渐渐感觉思维也都麻了!本文将基础的背包问题做个小结,方便以后翻阅。感兴趣的朋友也可以阅读一下~ ------------------------ (1)如何从n个重量和价值分别为Vi、Wi的物品中选择一或多个放入最大容纳量为S的背包使其总价值最大?
云海谷天
2022/08/09
1620
相关推荐
掌握套路,你也会用动态规划
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验