android 动态规划,动态规划算法讲解 – 巴黎高等计算机学院(ESI-SUPINFO)中国校区技术博客...

Rate this post

一、什么是动态规划思想:

我们在遇到很多的算法求解问题时,通常会被给出的复杂、繁琐的需求所吓倒,这导致我们失去冷静严密的思考逻辑而变得暴躁不已,最终放弃这一个算法题,但其实,很多时候,我们遇到的问题都是可以对其进行拆分和化简的。当我们学会合理的拆分、化简、提取关键步骤,很多的算法难题就会因人而结,而在诸多算法思路中,最常用,也是最好用的就是动态规划方法。

什么是动态规划呢?动态规划的其实就是用分治的思想来解决冗余,因此,动态规划算法是一种将问题划分为更小的、具有相同步骤的子问题,并在此基础上存储子问题的解,这样就可以做到而避免重复计算的子问题,以解决最优的算法策略。其实一般来讲,只要某一问题可以划分成更小的子问题,并且原始问题中的最优解包含了他的子问题的最优解,那么这时我们就可以考虑用动态规划的方法来解决。那么我们不难看出,动态规划法与分治法和贪心法类似,它们都是将问题分解为更小的、相似的子问题,然后通过对子问题进行操作和实现来给整个问题提供最优解。

二、经典的动态规划算法实例:

在上面我们介绍了动态规划算法的基本思想和操作过程,但是光以文字的方式绝对无法让我们吃透这个思想方法,所以我们不妨看几道经典的动态规划例题。

1、题目描述(据说是网易的算法题)

现在有n个学生站成一列,每个学生有自己的能力值,憨憨想从这 n 个学生中按照一定的顺序选取 k 名学生。现在要求相邻的两个学生的位置编号之差不超过 d,从而使得这 k 个学生的拥有的能力值乘积最大,要求返回这最大的乘积。

从题目中,我们不难看出,按照最基本的思路我们会不停的遍历这一列学生,然后不断累加他们的能力值并判断是否是最大。然后等遍历结束后输出这个值。但是这样的做法显然非常的消耗时间(即时间复杂度太大),那么进一步分析,在此题中,如果先求解在第i个学生的位置下,往后数j(j

代码如下:(所用语言是python3)

n=input()

a=[int(i) for i in raw_input().split()]

k,d=[int(i) for i in raw_input().split()]

# n=36

a_max=a_min=a

#轮询k-1趟即可

for i in range(0,k-1):

_max=[-float(‘inf’)]*n #将最大值的数组赋值无穷小

_min=[float(‘inf’)]*n #将最小值的数组赋值无穷大

for j in range(i+1,n):

if j<=d+i: #下面对应的min、max都是考虑到array[j]为负值的情况下

temp_max = max(max(ii*a[j] for ii in a_max[i:j]),max(ii*a[j] for ii in a_min[i:j]))

temp_min = min(min(ii*a[j] for ii in a_max[i:j]),min(ii*a[j] for ii in a_min[i:j]))

else:

temp_max = max(max(ii*a[j] for ii in a_max[j-d:j]),max(ii*a[j] for ii in a_min[j-d:j]))

temp_min = min(min(ii*a[j] for ii in a_max[j-d:j]),min(ii*a[j] for ii in a_min[j-d:j]))

_max[j]=temp_max #将最大值赋值给最终记录变量

_min[j]=temp_min #将最小值赋值给最终记录变量

a_max=_max

a_min=_min

print max(a_max) #直接输出最大能力值

从上述代码中我们就可以看出,我们不必每次都从最开始来遍历学生,因为能力值最大的部分一定在上一次遍历、比较厚的结果中出现,这样就大大简化了这个题的难度,当然我们需要考虑能力值为负的情况——因为能力值负数意味着对所求解提供负收益,那么我们就需要用同样的方法判断负值之后,求出最小(负)值,然后综合考虑。

2、 题目描述

现给出一个有n个正整数的数组A和一个整数sum,要求求出选择数组A中部分数字的和为sum的方案数。

那么,如果当两种选取方案存在有一个数字的下标不一样,我们就认为这是不同的组成方案。

例如:输入为两行:

第一行,两个正整数n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000)

第二行,n个正整数A[i](大小为32位整数),中间以空格隔开。

要求输出:所求的方案数量。

那么通过我们的分析,如果我们还是采用暴力拆解的方法,强行递归,无疑是耗时耗力的,并且数组的判断情况特别多,想要写出这些判断并且没有遗漏显然是很难的。

所以,采用如下的代码:(python3)

if __name__==’__main__’:

n, s=[int(i) for i in raw_input().split(‘ ‘)]

#在数组中不需要添加大于s的数

l=[int(i) for i in raw_input().split(‘ ‘) if int(i)0:

if j+l[i]<=s: #这一步是为了防止数组越界

temp[j+l[i]]+=result[j]

result=temp[:] #将最终结果以遍历的方法放入result

print result[s] #按要求输出最终结果

通过上面的代码,我们发现,在本题中,我们不需要一次又一次的计算数组然后进行比较,因为大于s的数字是不需要添加进目标数组的。有了这一步之后,王result中添加数组时,也就不用一次又一次地添加一个个“短组”了。

总而言之动态规划算法作为计算机算法中相当重要的方法之一,我们一定要有这个意识去掌握它和使用它,特别是在一个大问题是有多次从负的小问题构成的时候。但是这种算法其实是非常考验我们对问题的分析能力的,其实,在我们想清楚拆解的思路后,用代码来实现是非常容易的,特别是python这种库函数和辅助功能很多的语言来说,解决了思路问题,就等于解决了这个算法问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值