博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于python的动态规划经典问题(爬楼梯,取珠宝,最大子序列和,找零钱)
阅读量:6495 次
发布时间:2019-06-24

本文共 2360 字,大约阅读时间需要 7 分钟。

  hot3.png

1,爬楼梯问题

一个人爬楼梯,每次只能爬1个或两个台阶,假设有n个台阶,那么这个人有多少种不同的爬楼梯方法

动态规划的状态转移:第 i 个状态的方案数和第 i-1, i-2时候的状态有关,即:dp[i]=dp[i-1]+dp[i-2],dp表示状态矩阵。

def climb_stairs(n):    dp=[0]*n    dp[0]=1    dp[1]=2    for i in range(2,n):        dp[i]=dp[i-1]+dp[i-2]    return dp[n-1]

2,取珠宝问题

一条直线上,有n 个房间,每个房间数量不等的财宝,一个盗贼希望从房屋中盗取财宝,由于房屋有警报器,同时从相邻两个房间盗取珠宝就会触发警报,求在不触发警报的情况下,最多可获取多少财宝?

如有6个房间,每个房间珠宝数量为[5,2,6,3,1,7]

状态转移:

前1个房间可获取珠宝的最大数量:5;

前2个房间可获取珠宝的最大数量:5;

前3个房间可获取珠宝的最大数量:11;

前4个房间可获取珠宝的最大数量:11;

前5个房间可获取珠宝的最大数量:12;

可以发现,前i个房间最大可获取的数量和前i-1,i-2个房间可获取的最大珠宝数量,以及第i个房间的珠宝数量有关:第i个房间珠宝有两种方案,获取(总最大数量等于第i个房间的珠宝数量+前i-2个房间的珠宝最大数量)和不获取(总最大数量=前i-1个房间可获取珠宝的最大数量)。

即:dp[i]=max(dp[i-2]+value[i],dp[i-1]),dp表示状态矩阵。

def stealJewellery(value):    n=len(value)    dp=[0]*n    dp[0]=5    dp[1]=5    for i in range(2,n):        dp[i]=max(dp[i-2]+value[i],dp[i-1])    return dp[n-1]value=[5,2,6,3,1,7]print(stealJewellery(value))

3,最大子序列和问题

给定一个数组,求这个数组的连续子数组中,最大的那一段的和。

如数组 arr= [-2,1,-3,4,-1,2,1,-5,4]

状态转移:

 如果当前数组的值arr[i]加上第i-1个状态的值大于数组arr[i],第i个状态的值就等于arr[i]+dp[i-1],

否则,dp[i]=arr[i]。其中dp[i]记录的是以第i个数组结尾的最大字段和

记录当前最大的子序列和。即 dp[i]=max(dp[i-1]+arr[i],arr[i]),最大子序列和为max(dp)

def subsequenceSum(arr):    n=len(arr)    dp=[0]*n    dp[0] = arr[0]    for i in range(1,n):        dp[i]=max(dp[i-1]+arr[i],arr[i])    return max(dp)

4,找零钱问题

已知不同面值的钞票,求如何用最少数量的钞票组成某个金额,求可以使用的最少钞票数量。如果任意数量的已知面值钞票都无法组成该金额,则返回-1

假设coins=[1,2,5,7,10],金额:amount=14,dp[i]表示金额 i 的最优解。

金额14的最后一张面额可能由coins里面的任意一张得到,即:

14=coins[0]+(14-coins[0]) \Rightarrow14=1+13 \Rightarrow dp[14]=1+dp[13]

14=coins[0]+(14-coins[1]) \Rightarrow14=2+12 \Rightarrow dp[14]=1+dp[12]

14=coins[0]+(14-coins[2]) \Rightarrow14=5+9 \Rightarrow dp[14]=1+dp[9]

14=coins[0]+(14-coins[3]) \Rightarrow14=7+7 \Rightarrow dp[14]=1+dp[7]

14=coins[0]+(14-coins[4]) \Rightarrow14=10+4 \Rightarrow dp[14]=1+dp[4]

具体最后一张选了哪个面额,就要看哪个面额情况下总拼凑数量最少。即:dp[i]=min(dp[i],dp[i-coins[j]]+1),当计算到金额14时候,小于14的金额的最小数量都已经求出并存储在dp[i]里面,此时只需要直接取出比较即可。最终函数返回dp[14]即为所求的最少数量。

 

求解代码一共有两个for循环,一个是金额从0-amount的最少数量(dp[i]),另外一个是面额数量组合(coins[j])。dp[i]的初始值都设置为amount+1,当所有的coins都无法拼凑当前金额 i 的时候,dp[i] = amount+1 此时dp[i] 大于amount,所以函数返回-1。

def coinChange(coins,amount):    dp=[amount+1]*(amount+1)    dp[0]=0    for i in range(1,amount+1):        for j in range(len(coins)):            if coins[j]<=i:                dp[i]=min(dp[i],dp[i-coins[j]]+1)    if dp[amount]>amount:        return -1    else:        return dp[amount]coins=[1,2,5,7,10]print (coinChange(coins,14))

转载于:https://my.oschina.net/zhxx/blog/3042450

你可能感兴趣的文章
20步打造最安全的Nginx Web服务器
查看>>
WP8:Unity3D之间的值传递
查看>>
string与数值之间的转换
查看>>
Windows系统安装Oracle 11g客户端
查看>>
怎样写出一个较好的高速排序程序
查看>>
【动态规划】最长公共子序列与最长公共子串
查看>>
要立刷金组flag了T_T
查看>>
Swift常量和变量
查看>>
GNU Make chapter 2 —— Makefile 介绍
查看>>
[转]在Eclipse中使用JUnit4进行单元测试(中级篇)
查看>>
gdb图形化调试工具总结
查看>>
白话经典算法系列之七 堆与堆排序
查看>>
微软职位内部推荐-SDEII
查看>>
Windows下FFmpeg高速入门
查看>>
【分享】 IT囧事
查看>>
Android安卓开发中图片缩放讲解
查看>>
【Java】Lucene检索引擎详解
查看>>
Cts框架解析(7)-任务运行的调度室
查看>>
SDN:软件定义网络
查看>>
1.1GTK+ 的简单程序HelloWorld
查看>>