动态规划分析总结——怎样设计和实现动态规划算法

进行算法设计的时候,时常有这种体会:假设已经知道一道题目能够用动态规划求解,那么非常easy找到对应的动态规划算法并实现;动态规划算法的难度不在于实现,而在于分析和设计—— 首先你得知道这道题目须要用动态规划来求解。

本文,我们主要在分析动态规划在算法分析设计和实现中的应用,解说动态规划的原理、设计和实现。在非常多情况下,可能我们能直观地想到动态规划的算法。可是有些情况下动态规划算法却比較隐蔽。难以发现。

本文。主要为你解答这个最大的疑惑:什么类型的问题能够使用动态规划算法?应该怎样设计动态规划算法?

动态规划第一讲——缓存与动态规划

一、缓存与动态规划

例一:有一段楼梯有10级台阶。规定每一步仅仅能跨一级或两级,要登上第10级台阶有几种不同的走法?

分析:非常显然,这道题的相应的数学表达式是F(n)=F(n-1) + F(n-2);当中F(1)=1, F(2)=2。

非常自然的状况是,採用递归函数来求解:

int  solution(int n){
	if(n>0 && n<2) return n;
	return solution(n-1) + solution(n-2);
}


假设我们计算F(10), 先须要计算F(9) F(8); 可是我们计算F(9)的时候,又须要计算F(8),非常明显,F(8)被计算了多次。存在反复计算;同理F(3)被反复计算的次数就很多其它了。算法分析与设计的核心在于 依据题目特点,降低反复计算。  在不改变算法结构的情况下。我们能够做例如以下改进:

int dp[11];
int  solution(int n){
	if(n>0 && n<2) return n;
	if(dp[n]!=0) return dp[n];
	dp[n] = solution(n-1) + solution(n-2);
	return  dp[n];
}

这是一种递归形似的写法,进一步,我们能够将递归去掉:

int  solution(int n){
	int dp[n+1];
	dp[1]=1;dp[2]=2;
	for (i = 3; i <= n; ++i){
		dp[n] = dp[n-1] + dp[n-2];
	}
	return  dp[n];
}

当然,我们还能够进一步精简。只用两个变量来保存前两次的计算结果; 这个算法留待读者自己去实现

例二:01背包问题

有n个重量和价值分别为vector<int> weight, vector<int> value的物品;背包最大负重为W,求能用背包装下的物品的最大价值?

输入:n =4

weight=2, 1, 3, 2

value =3, 2, 4, 2

W=5

输出=7

思考一:我们能够採用穷举法,列出n个物品的全部组合形式,从中选取符合条件的最大价值:

採用穷举法,必定须要可以举出全部状态,不重不漏;而怎样穷举,方法多种多样,我们的任务是要穷举有n个元素组成的全部子集。

而穷举的方法主要有两种—— 递增式(举出1~100之内的全部数字, 从1到100);和分治式的穷举(比如举出n个元素的集合。包括两种—— 含有元素a和不含元素a的)。于是,我们基于穷举法得到背包问题的第一种算法—— 递归与分治。

int rec(int i, int j){//从i到n号物品,选择重量不大于j的物品的最大价值
	int res;
	if(i==n){
		res=0;
	}
	else if(j< w[i]){
		res = rec(i+1, j);
	}
	else{
		res = max(rec(i+1, j), rec(i+1, j-w[i])+v[i]);
	}
	return res;
}

调用res(0, W), 就可以得到结果. 时间复杂度O(2^n);我们来分析一下递归调用的情况。

为了偷懒,最后一行没有画出来,可是注意红色的部分。我们会

时间: 2024-10-13 01:42:42

动态规划分析总结——怎样设计和实现动态规划算法的相关文章

动态规划分析总结——如何设计和实现动态规划算法

进行算法设计的时候,时常有这样的体会:如果已经知道一道题目可以用动态规划求解,那么很容易找到相应的动态规划算法并实现:动态规划算法的难度不在于实现,而在于分析和设计-- 首先你得知道这道题目需要用动态规划来求解.本文,我们主要在分析动态规划在算法分析设计和实现中的应用,讲解动态规划的原理.设计和实现.在很多情况下,可能我们能直观地想到动态规划的算法:但是有些情况下动态规划算法却比较隐蔽,难以发现.本文,主要为你解答这个最大的疑惑:什么类型的问题可以使用动态规划算法?应该如何设计动态规划算法? 动

深入浅出分析MySQL索引设计背后的数据结构

在我们公司的DB规范中,明确规定: 1.建表语句必须明确指定主键 2.无特殊情况,主键必须单调递增 对于这项规定,很多研发小伙伴不理解.本文就来深入简出地分析MySQL索引设计背后的数据结构和算法,从而可以帮你释疑如下问题: 1.为什么innodb表需要主键? 2.为什么建议innodb表主键是单调递增? 3.为什么不建议innodb表主键设置过长? B-tree(多路搜索树,并不是二叉的)是一种常见的数据结构.使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度.B通常

sicily 1176. Two Ends (Top-down 动态规划+记忆化搜索 v.s. Bottom-up 动态规划)

DescriptionIn the two-player game "Two Ends", an even number of cards is laid out in a row. On each card, face up, is written a positive integer. Players take turns removing a card from either end of the row and placing the card in their pile. T

敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)

邀请函:尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧.时间:2014.06.07(周六),上午9:00-12:00,下午14:00-17:30(时长6.5小时)地点:郑州市畜牧路16号牧业经济学院实验楼B座2518(可乘坐B11.909.962.47路等公交车到老长途汽车北站下车畜牧路向东300米路北)软件知识原创基地www.umlonline.or

【转载】算法设计之五大常用算法设计方法总结

转载自http://blog.csdn.net/zolalad/article/details/11393915 算法设计之五大常用算法设计方法总结 一.[分治法]  在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)--等.任

GPS部标平台的架构设计(五)-地图服务算法库

GPS平台,需要和各种地图打交道,需要解决以下的问题: 1.坐标偏移,这个不用多说,需要将原始坐标加偏,然后在百度地图或谷歌上显示出来,需要注意的是百度地图的加偏是偏上再偏,谷歌.高德地图等是火星坐标: 2.坐标解偏,或者纠偏,这个我们也是需要的,因为当用户在地图上画出的各种区域,标注,发送到后台存储的坐标都是基于地图所采用的坐标系统,因而是偏移的,这就面临一个严重的问题,因为在部标808协议中,对于区域报警,需要将区域的顶点坐标,下发给终端,终端在实际运行中,不断用GPS坐标和区域坐标进行比对

OpenStack_Swift源代码分析——创建Ring及加入?设备源代码算法具体分析

1 创建Ring 代码具体分析 在OpenStack_Swift--Ring组织架构中我们具体分析了Ring的具体工作过程,以下就Ring中添加?设备,删除设备,已经又一次平衡的实现过程作具体的介绍. 首先看RingBuilder类 def __init__(self, part_power, replicas, min_part_hours): #why 最大 2**32 if part_power > 32: raise ValueError("part_power must be a

通过分析 JDK 源代码研究 TreeMap 红黑树算法实现

TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点. TreeSet 和 TreeMap 的关系 为了让大家了解 TreeMap 和 TreeSet 之间的关系,下面先看 TreeSet 类的部分源代码: public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializab

C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法

STL实践与分析 --容器特有的算法 与其它顺序容器所支持的操作相比,标准库为list容器定义了更精细的操作集合,使它不必仅仅依赖于泛型操作.当中非常大的一个原因就是list容器不是依照内存中的顺序进行布局的,不支持随即訪问,这样,在list容器上就不能使用随即訪问迭代器的算法,如sort等:还有其它的一些算法如:merge.remove.reverse和unique,尽管能够用在list上,但却付出了高昂的性能代价.因此标准库结合list的内部结构,编写出了更快算法: list容器特有的操作