1、算法设计分析,算法设计与分析复习总结,算法设计分析,算法设计与分析课程是计算机专业本科的专业必修课。 这是一门面向设计的课程。 设立本课程的是为了适应21世纪我国计算机科学技术及软件工程人才培养的需要,培养学生设计和分析算法的能力。 通过学习本课程,应该掌握计算机软件常用的几种算法。并可以对算法的复杂性进行分析,从而能够在实际工作中根据具体问题设计和优化算法。,算法设计分析,算法设计分析正是一种面向设计,且处于计算机学科核心地位的教育课程。通过对计算机算法系统的学习与研究。 掌握算法设计的主要方法。 培养对算法的计算复杂性正确分析的能力。 为独立设计算法和对算法进行复杂性分析奠定坚实的理论基础
2、。 这对每一位从事计算机系统结构、系统软件和应用软件研究与开发的科技工作者都是非常重要和必不可少的。,算法设计分析,第一章 算法引论,一、学习要求 通过本章的学习,要求了解该课程的基本框架,理解算法的概念,如何来表达算法,同时还简要介绍如何使用计算机程序设计语言来描述算法。 本章要了解算法与程序的区别,算法在计算机及软件领域的作用和地位,理解使用抽象数据来表达算法,重点掌握如何使用计算机程序设计语言来描述算法。 二、课程内容 1算法的基本概念 2表达算法的抽象机制 3使用语言来描述算法 4算法的复杂性分析,算法设计分析,1.1算法特性,概括起来,算法有以下几个特性: 1 确定性; 2 可实现性
3、; 3 具有数据输入;4 具有数据输出;5 有穷性。,算法设计分析,例:选择题:下面对算法描述正确的一项是:(C ) A. 算法只能用自然语言来描述 B. 算法只能用图形方式来表示 C. 同一问题可以有不同的算法 D. 同一问题的算法不同,结果必然不同,算法设计分析,程序与算法不同。 程序是算法用某种程序设计语言的具体实现。程序可以不满足算法的性质4 。例如操作系统,它是一个在无限循环中执行的程序,因而不是一个算法。 然而我们可把操作系统的各种任务看成是一些单独的问题,每一个问题由操作系统中的一个子程序通过特定的算法来实现。该子程序得到输出结果后便终止。,算法设计分析,算法指的是(B) A计算
4、程序 B. 解决问题的计算方法 C. 排序算法 D. 解决问题的有限运算序列 计算机算法指的是解决问题的计算方法。描述算法可以有多种方式,如自然语言方式和表格方式等。 算法的实现工具的是语言。算法是对方法和步骤的描述。,算法设计分析,下面对算法描述正确的一项是:( C ) A. 算法只能用自然语言来描述 B. 算法只能用图形方式来表示 C. 同一问题可以有不同的算法 D. 同一问题的算法不同,结果必然不同,算法设计分析,对于算法的概念,不同的教材叙述方式不尽相同,以下是常见的几种说法。 算法就是一组有穷的规则,它们规定了解决某一特定类型问题的一系列运算 Thomas H. Cormen 等人在
5、“Introduction to Algorithms”一书中将算法描述为:算法是任何定义好了的计算程式,它取某些值或值的集合作为输入,并产生某 些值或值的集合作为输出。,算法设计分析,算法的下五个特性 : 输出 一个算法产生一个或多个输出,它们是同输入有某种特定关系的量。确定性 算法的每一种运算(包括判断)必须要有确切的定义,即每一种运算应该执行何种动作必须是相当清楚的、无二义性的。有限性 算法中每条指令的执行次数有限,执行每条指令的时间也有限,因此一个算法总是在执行了有穷步之后终止。,算法设计分析,可实现性(或可行性) 此性质是指算法中有待实现的运算都是相当基本的,每种运算至少在原理上能由
6、人用纸和笔在有限的时间内完成。其中这一条也是最重要的,一个算法没有可实现性也就失去了存在的价值。,算法设计分析,1.2 算法复杂性分析,程序性能是指运行一个程序所需的内存大小和时间多少。 程序的性能一般指程序的空间复杂性和时间复杂性。 性能评估主要包含两方面,即性能分析与性能测量measurement)前者采用分析的方法,后者采用实验的方法。,算法设计分析,算法复杂性是算法运行所需要的计算机资源的量,这个量应该只依赖于算法要解的问题的 规模 、 算法的输入 和 算法本身的函数 。 算法复杂性是算法运行所需要的计算机资源的量,需要的空间资源的量称为空间复杂性。(),算法设计分析,算法分析的两个主
7、要方面是:( A ) A. 空间复杂性和时间复杂性 B. 正确性和简明性 C可读性和文档性 D. 数据复杂性和程序复杂性,算法设计分析,考虑时间复杂性的理由,某些计算机用户需要提供程序运行时间的上限。 所开发的程序需要提供一个满意的实时反应。,算法设计分析,程序=算法+数据结构,软件:刻画现实世界,解决现实世界中的问题。 语言:实现的工具。 算法:解的描述数据结构:现实世界的数据模型。 程序=算法+数据结构,算法设计分析,1.3 时间复杂性,时间复杂性的构成: 一个程序所占时间T (P)编辑时间+运行时间: 编译时间与实例特征无关,而且,一般情况下,一个编译过的程序运行若干次,所以,人们主要关
8、注的是运行时间,记做T (P)实例特征) 如果了解所用编辑器的特征,就可以确定代码P进行加、减、乘、除、比较、读、写等所需的时间,从而得到计算T (P)的公式。 令n代表实例特征(这里主要是问题的规模),则有如下的表示式:,算法设计分析,一个操作所需的时间取决于操作数的类型(int, float, double等等),所以,有必要对操作按照数据类型进行分类; 在构思一个程序时,影响时间的许多因素还是未知的,所以,在多数情况下仅仅是对t进行估计。 估算运行时间的方法: A.找一个或多个关键操作,确定这些关键操作 所需要的执行时间(对于前面所列举的四种算术运算及比较操作,一般被看作是基本操作,并约
9、定所用的时间都是一个单位)。 B.确定程序总的执行步数。,算法设计分析,三种情况下的时间复杂性,本书只考虑三种情况下的时间复杂性,即最坏情况、最好情况和平均情况下的时间复杂性以上三种情况下的时间复杂性从不同角度来反映算法的效率,各有其局限性,也各有各的用处。 实践表明可操作性最好且最有实际价值的是最坏情况下的时间复杂性。 本书对算法的时间复杂性分析的重点将放在这种情形上。,算法设计分析,设三个函数f,g,h分别为f(n)=100n3+n2+1000,g(n)=25n3+5000n2,h(n)=n1.5+5000nlgn,请判断下列关系不成立的是:( C ) A. f(n)=O(g(n) B.
10、g(n)=O(f(n) Ch(n)=O(f(n) D h(n)=O(nlgn),算法设计分析,设T(n) 是算法A 的复杂性函数。一般说来,当n单调增加趋于 时,T(n) 也将单调增加趋于 。如果存在函数T(n) ,使得当n 时有(T(n) T(n) /T(n) 0,则称T(n) 是T(n) 当n 时的渐近性态,或称T(n)是算法A 当n 的渐近复杂性。 因为在数学上,T(n) 是T(n) 当n 时的渐近表达式,T(n) 是T(n) 中略去低阶项所留下的主项,所以它无疑比T(n) 来得简单。 进一步分析可知,要比较两个算法的渐近复杂性的阶不相同时,只要确定出各自的阶,就可以哪一个算法的效率高。
11、 换句话说,渐近复杂性分析只要关心T(n) 的阶就够了,不 必关心包含在T(n) 中的常数因子。,算法设计分析,当问题的规模n趋向无穷大时, B 的数量级(阶)称为算法的渐进时间复杂度。 A.空间复杂度 B.时间复杂度 C.冗余度 D.迭代次数,算法设计分析,简化算法复杂性分析的方法,简化算法复杂性分析的方法即是只考虑当问题的规模充分大时,算法复杂性 在渐近意义下的阶。,算法设计分析,在下面的讨论中,用f (n)表示一个程序的时间或空间复杂性,它是实例特征n(一般是输入规模)的函数。 对于一个程序的时间或空间需求是一个非负的实数,我们假定函数f (n)对于n的所有取值均为非负实数,而且n=0,
12、算法设计分析,渐近符号O 的定义,用f(n)表示一个程序的时间或空间复杂性,它是实例特征n(一般是输入规模)的函数。 由于一个程序的时间或空间需求是一个非负的实数,我们假定函数f(n)对于n 的所有取值均为非负实数,而且还可假定n=0。 f(n)=O(g(n)当且仅当存在正的常数c 和n0,使得对于所有的n=n0,有f(n)=cg(n)。 此时,称g(n)是f(n)的一个上界。,算法设计分析,渐近符号O 的定义的注意事项,用来作比较的函数g(n)应该尽量接近所考虑的函数f(n). 3n+2=O(n的2次方) 松散的界限; 3n+2=O(n) 较好的界限。,算法设计分析,通常用来表示时间算法的有
13、以下六种多项式: 按从小到大的顺序排列 :,算法设计分析,f(n)=O(g(n)不能写成g(n)=O(f(n),因为两者并不等价。 实际上,这里的等号并不是通常相等的含义。 按照定义,用集合符号更准确些: O(g(n)=f(n)|f(n)满足:存在正的常数c 和n0,使得当n=n0 时,f(n)=cg(n) 所以,人们常常把f(n)=O(g(n)读作:“f(n)是g(n)的一个大O 成员”。,算法设计分析,的渐近表达式是 或 下面程序段的时间复杂度是 for (i=0; in; i+)for (j=0; jn; j+)Aij=0;,算法设计分析,符号 的定义,f (n) = (g(n) 当且仅
14、当存在正的常数c 和0 n ,使得对于所有的On n ,有f (n) c(g(n)。 此时,称g(n)是f(n)的一个下界。 函数f 至少是函数g 的c 倍,除非On n 。 即是说,当n 充分大时,g 是f 的一个下界函数,在相差一个非零常数倍的情况下。,算法设计分析,O有如下运算性质,算法设计分析,例如:如果那么:,算法设计分析,渐近意义下的五个记号的区别:、和,设f(N)和g(N)是定义在正数集上的正函数。 (1)如果存在正的常数C和自然数N0,使得当NN0时有f(N)Cg(N)。 则称函数f(N)当N充分大时上有界,且g(N)是它的一个上界,记为f(N)=(g(N)。 这时我们还说f(
15、N)的阶不高于g(N)的阶。,算法设计分析,(2)如果存在正的常数C和自然数N0,使得当NN0时有f(N)Cg(N),则称函数f(N)当N充分大时下有界,且g(N)是它的一个下界,记为f(N)=(g(N)。 这时我们还说f(N)的阶不低于g(N)的阶。,算法设计分析,(3)定义f(N)=(g(N)则f(N)=(g(N) 且f(N)=(g(N)。这时,我们说f(N)与g(N)同阶。 (4)如果对于任意给定的0,都存在非负整数N0,使得当NN0时有f(N)g(N), 则称函数f(N)当N充分大时比g(N)低阶,记为f(N)= o(g(N)。 (5)f(N)=(g(N)定义为g(N)=o(f(N)。
16、,算法设计分析,例: 的渐近表达式是。按照渐近阶比较大小 ,算法设计分析,第二章 递归与分治策略,一、学习要求:通过本章的学习,要求学生了解递归与分治的概念及相互关系,理解递归与分治算法策略的基本思想,掌握使用递归与分治策略解决经典的问题,并对算法进行复杂性分析。 二、课程内容 1递归的概念 递归的含义 使用递归的方法解决实际的问题 阶乘函数的递归表达式 Fabonacci数列的递归表达式 使用递归方法解决Hanoi塔问题,算法设计分析,2分治法的基本思想 分治的含义 分治算法的设计模式 分治法的效率分析 3分治策略应用实例 二分搜索算法 大整数的乘法 Stassen矩阵乘法 棋盘覆盖游戏 合
17、并排序算法 快速排序算法,算法设计分析,分治法的设计思想,分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。如果原问题可分割成k个子问题,1k=n且这些子问题都可解,并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。,算法设计分析,由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。 在这种情况下反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终位子问题缩小到很容易求出其解。 这样,就自然导致递归算法的产生。分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。,
18、算法设计分析,分治法的设计思想是: 将一个难以直接解决的大规模问题,分割成些规模较小的相同问题,以便各个击破,分而治之 。 二分搜索算法是运用分治策略的典型例子。 (对),算法设计分析,21 递归的概念,直接或间接地调用自身的算法称为递归算法。一个使用函数自身给出定义的函数称为递归函数。 在计算机算法设计与分析中,使用递归技术他往使函数的定义和算法的简洁且易于理解。 有些数据结构如二又树等,由于其本身的递归特性、特别适合用递归的形式来描述。 还有一些问题,虽然其本身并没有明显的递归结构但用递归技术来求解使设计出的算法简洁易懂且易于分析。,算法设计分析,递归策略的注意几点,一个递归定义必须是有确
19、切合义的,也就是说,必须一步比一步简单,最后是有终结的,决不能无限循环下去。 在f(n)的定义中,当n为0时定义一个已知数a,是最简单的情况,称为递归边界,它本身不再使用递归的定义。,算法设计分析,有如下递归过程:void reverse (int m) printf(“%d”,n%10);if(n/10!=0)reverse(n/10); 调用语句reverse(687)的结果是_7 8 6,算法设计分析,与递推一样,每一个递归定义都有其边界条件。但不同的是,递推是内边界条件出发通过递推式求f(n)的值t从边界到求解的全过程十分清楚 而递归则是从函数本身出发来达到边界条件。,算法设计分析,在
20、通往边界条件的递归调用过程中,系统用堆栈把每次调用的中间结果(局部变量和返回地址值)保存起来,直至求出递归边界值f(0)a,然后返回调用函数。,算法设计分析,返回过程中,中间结果相继出栈恢复,f(1)g(1,a),f(2)g(2f(1), 直至求出f(n)g(n,f(n1)。 由此可见,递归算法的效率往往很低,费时和费内存空间。 但是递归也有其长处,能使一个蕴含递归关系且结构复杂的程序简洁精炼,增加可读性。 特别是在难于找到从边界到解的全过程的情况下,如果把问题推进一步,其结果仍维持原问题的关系,则采用递归算法编程比较合适。,算法设计分析,回溯法对解空间进行深度优先搜索,一般使用递归方法实现回
21、溯法: void backtrack (int t) if (tn) output(x);elsefor (int i=f(n, t); i=g(n,t); i+) xt=h(i);if (constraint(t) A. backtrack(t+1) B. backtrack(t-1) C. backtrack(t) D. backtrack(t+2),算法设计分析,递归按其调用方式分:直接递归递归过程P直接自己调用自己; 间接通归:即P包含另一过程D,而D又调用 直接或间接的调用自身的算法称为A。 A递归算法 B 贪心算法 C迭代算法 D动态规划算法,算法设计分析,阶乘函数用递归定义 Pu
22、blic static int factorial(int n) if(n=0) return 1; return B ; A n*factorial(n) B n*factorial(n-1) C n*factorial(n-2) D n*factorial(n+1),算法设计分析,递归算法的优点是结构清晰,可读性强,运行效率高。(错) 直接或间接地调用自身的算法称为 递归算法 。,算法设计分析,递归算法适用的场合,数据的定义形式按递归定义。如裴波那契数列的定义:fn=fn-1+fn-2,if f0=1,f1=2. 这类递归问题可转化为递推算法,递归边界作为递推的边界条件 数据之间的关系(即
23、数据结构)按递归定义。如树的遍历图的搜索等 以及问题解法按递归算法实现。例如回溯法等,算法设计分析,递归算法不能适用以下场合(B)。 A.数据的定义形式按递归定义 B.数据之间的关系(即数据结构)按递归定义 C.问题解法按递归算法实 D.概率问题,算法设计分析,分治法与递归法的联系与区别,有许多算法在结构是递归的:为了解决一个给定问题,算法要一次或多次地调用其 自身来解决相关的子问题。 这些算法通常采用分治策略:将原问题分成n个规模较小而结构结原问题相似的子问题。 递归地解这些子问题,然后合并其结果就得到原问题的解。 n2时的分治法又称二分法。,算法设计分析,用分治法求解一个问题,所需的时间是
24、由子问题的个数, 大小以及把这个问题分解为子问题所需的工作总里来确定的。 一般来说,二分法(即把任意大小的问题尽可能地等分为两个子问题)较为有效。,算法设计分析,从分治法的一般设计模式可以看出,用它设计出的程序一般是一个递归过程。因此,分治法的计算效率通常可以用递归方程来进行分析。(对) 分治法算法的最关键步骤是分解。(错) 二分搜索算法运用的是分治策略。 (对),算法设计分析,分治法每一层递归上的三个步骤,简答: 分治法在每一层递归上都三个步骤? 分解:将原问题分解成一系列子问题; 解决:递归地解各子问题。若子问题足够小,则直接解: 合并:将子问题的结果合并成原问题的解; 快速排序算法是基于
25、分治策略的一个算法。其基本思想是,对于输入的子数组ap:r,按以下3个步骤进行排序:分解、递归求解、合并。,算法设计分析,应用分治法的两个前提是(A ) A. 问题的可分性和解的可归并性 B. 问题的可分性和解的存在性 C. 问题的复杂性和解的可归并性 D. 问题的可分性和解的复杂性,算法设计分析,有的同学选择为B。这道题仍然考察的对分治法基本思想的理解。 分治法的基本思想 任何一个可以用计算机求解的问题所需的计算时间都与其规模N有关。问题的规模越小, 越容易直接求解,解题所需的计算时间也越少。 例如,对于n个元素的排序问题,当n=1时,不需任何计算;n=2时,只要作一次比较即可排好序;n=3
26、时只要作3次比较即可,。而当n较大时,问题就不那么容易处理了。 要想直接解决一个规模较大的问题,有时是相当困难的。,算法设计分析,分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。 如果原问题可分割成k个子问题(1kn),且这些子问题都可解,并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。 由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供 了方便。,算法设计分析,在上述情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。 分
27、治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。,算法设计分析,就本题而言,分治法的适用条件分治法的适用条件 分治法所能解决的问题一般具有以下几个特征: 1)该问题的规模缩小到一定的程度就可以容易地解决; 这一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加,算法设计分析,2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质; 这条特征是应用分治法的前提,它也是大多数问题可以满足的,此特征反映了递归思想的应用 合并排序算法的基本思想是将待排序的元素分成大小大致相同的2个子集合,分别对2个子集合进行排序,最终将排
28、好序的子集合合并成为所要求的排好序的集合。,算法设计分析,3)利用该问题分解出的子问题的解可以合并为该问题的解; 这条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征, 如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑贪心法或动态规划法。,算法设计分析,4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。 这条特征涉及到分治法的效率,如果各子问题是不独立的,则分治法要做许多不必要的 工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。 因此本题的正确答案为: A. 问题的可分性和解的可归并性,算法设计分析,排序的分类,插入排序
29、,交换排序,选择排序,归并排序和计数排序等等 复杂度分类 O(n2) O(nLogn) O(dn) 排序进行的操作 比较和移动,第六章:排序和查找,算法设计分析,根据排序元素所在位置不同,排序非内排序和外排序。 (对),算法设计分析,快速排序,基本思想 通过一趟排序将纪录分割,其中一部分关键字均比另一部分小;然后再分别对这两部分进行排序; 通常选取序列的第一个纪录作为比较的参照(称为支点Pivot),然后将关键字小的排在其前,大的排在其后,并以此时关键字的位置将序列分成两部分,再对两部分进行快速排序; 因此快速排序是一个递归的算法,算法设计分析,实现快速排序算法如下: private stat
30、ic void quickSort(int p ,int r) if(pr))int q=partition(p,r); /以确定的基准元素ap对子数组ap;r进行划分A /对左半段排序quickSort(q+1,r); /对右半段排序 A. quickSort(p,q-1) B. quickSort(p+1,q-1) C. quickSort(p,q+1) D. quickSort(p,q-2),算法设计分析,.快速排序的平均复杂度为O(n2)。 (错) 快速排序的平均运行时间为 :( C ) A. O(n) B. O(n2) C. O(nlgn) D. O(lgn),算法设计分析,归并排序
31、,归并的含义: 将两个有序的序列合并形成一个新的有序序列 归并排序的过程: 先将序列视为n个有序的子序列,进行两两归并,然后再两两进行归并,直至形成一个序列 归并排序的核心算法: 两个有序序列合成一个序列 归并排序 需要和待排记录等量的空间 算法是递归的,算法设计分析,合并排序法的基本思想是:将待排序元素分成大小大致相同的C个子集合,分别对每个子集合进行排序,最终将排好序的子集合合并成为所要求的排好序的集合。 A . 4 B. 3 C. 2 D. 5,算法设计分析,合并排序算法是用 分支策略 实现对n各元素进行排序的算法。,算法设计分析,三 动态规划算法,学习要求 通过本章的学习: 要求了解动
32、态规划的基本思想; 掌握设计动态规划算法的步骤; 学会使用动态规划方法分析和解决实际的问题; 并对算法进行复杂性分析。,算法设计分析,课程内容,1动态规划算法介绍: (1)动态规划算法的基本思想 (2)动态规划算法与分治算法的区别 (3)动态规划算法的设计步骤 (4)动态规划算法的基本要素 2使用动态规划算法解决实际问题: 矩阵连乘问题 最长公共子序列问题 凸多边形最优三角剖分 多边形游戏 图像压缩 0-1背包问题,算法设计分析,动态规划算法基本概念,要了解动态规划的概念,首先要知道什么是多阶段决策问题。 多阶段决策问题 如果一类活动过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策(
33、采取措施),一个阶段的决策确定以后,常常影响到下一个阶段的决策,从而就完全确定了一个过程的活动路线,则称它为多阶段决策问题。,算法设计分析,动态规划算法基本思想,动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。 与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是互相独立的。 若用分治法解这类问题,则分解得到的子问题数目太多,以至于最后解决原问题需要耗费指数时间。,算法设计分析,给定若干物品的重量和价值,以及一个背包的容量上限。求出一种方案使的背包中存放物品的价值最高。这个问题除了可以考虑回溯法和分
34、支限界法之外,还可以用动态规划的方法解决。 (对),算法设计分析,适合于用动态规划求解的问题经过分解后得到子问题与分治法不同,它们往往是( B )。 A.互相独立的 B.互相不独立 C.互相交叉的 D.任意的,算法设计分析,动态规划算法可以有效地解0-1背包问题。(对) 动态规划算法 适用于解最优化问题。,算法设计分析,不同子问题的数目常常只有多项式量级。在用分治法求解时,有些子问题被重复计算了许多次。 如果能够保存已解决的子问题的答案,所在需要时再找出已求得的答案,就可以避免大量重复计算从而得到多项式时间算法。 为了达到这个目的,可以用个表来记录所有已解决的子问题的答案。 不管该于问题以后是
35、否被用到只要它被计算过,就将其结果填人表中。这就是动念规划法的基本思想。具体的动态规划算法是多种多样的,但它们具有相同的填表格式。,算法设计分析,动态规划的定义,我们将具有明显的阶段划分和状态转移方程的动态规划称为标准动态规划。 这种标准动态规划是在研究多阶段决策问题时推导出来的,具有严格的数学形式,适合用于理论上的分析。 在实际应用中,许多问题的阶段划分并不明显,这时如果刻意地划分阶段法反而麻烦。 一般来说,只要该问题可以划分成规模更小的子问题,并且原问题的最优解中包含了子问题的最优解(即满足最优子化原理),则可以考虑用动态规划解决。,算法设计分析,动态规划的实质,动态规划的实质是分治思想和
36、解决冗余 因此,动态规划是一种将问题实例分解为更小的、相似的子问题,并存储子问题的解而避免计算重复的子问题,以解决最优化问题的算法策略。,算法设计分析,动态规划法与其他算法的联系,动态规划法与分治法和贪心法类似,它们都是将问题实例归纳为更小的、相似的子问题,并通过求解子问题产生一个全局最优解。 其中贪心法的当前选择可能要依赖已经作出的所有选择,但不依赖于有待于做出的选择和子问题。,算法设计分析,因此贪心法自顶向下,一步一步地作出贪心选择 而分治法中的各个子问题是独立的(即不包含公共的子子问题) 因此一旦递归地求出各子问题的解后,便可自下而上地将子问题的解合并成问题的解。 但不足的是,如果当前选
37、择可能要依赖子问题的解时,则难以通过局部的贪心策略达到全局最优解 如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题。,算法设计分析,动态规划主要应用方面,动态规划主要应用于最优化问题 这类问题会有多种可能的解,每个解都有一个值,而动态规划找出其中最优(最大或最小)值的解。 若存在若干个取最优值的解的话,它只取其中的一个。在求解过程中,该方法也是通过求解局部子问题的解达到全局最优解.,算法设计分析,动态规划法的基本步骤是(D)。 (1)找出最优解的性质,并刻画其结构特征; (2)递归地定义最优值 (3)以自底向上的方式计算出最优值 (4)根据计算最优值时得到的信息,构造
38、最优解 A(1)(3) B.(1) C.(2)(4) D.(1)(4),算法设计分析,动态规划算法的基本要素是(A)。 (1)最优子结构 (2)重叠子问题 (3)最优解 (4)递归定义 A(1)(2) B. (1)(3) C.(2)(4) D.(2)(3),算法设计分析,与分治法和贪心法的不同,动态规划与分治法和贪心法不同的是: 动态规划允许这些子问题不独立,(亦即各子问题可包含公共的子子问题)也允许其通过自身子问题的解作出选择 该方法对每一个子问题只解一次,并将结果保存起来,避免每次碰到时都要重复计算。,算法设计分析,对同一个问题,动态规划算法和分治算法的计算复杂性是一样的。(错) 在动态规
39、划算法中,问题的最优子结构性质使我们能够以 D的方式递归地从子问题的最优解逐步构造出整个问题的最优解。 A.自左向右 B.自右向左 C.自上向下 D.自底向上,算法设计分析,与分治法不同的是,适合于用动态规划求解的问题, D A经分解得到子问题往往是任意的 B经分解得到子问题往往是互相独立的 C经分解得到子问题往往是互相交叉的 D经分解得到子问题往往不是互相独立的,算法设计分析,动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式做出相继的贪心选择,每做出一次贪心选择就将所求问题简化为规模更小的子问题。,算法设计分析,动态规划法的关键,动态规划法所针对
40、的问题有一个显著的特征,即它所对应的子问题树中的子问题呈现大量的重复。 动态规划法的关键就在于:对于重复出现的子问题,只在第一次遇到时加以求解,并把答案保存起来,让以后再遇到时直接引用,不必重新求解。,算法设计分析,动态规划算法的基本步骤,设计一个标准的动态规划算法,通常可按以下几个步骤进行: (1)划分阶段 (2)选择状态 (3)确定决策并写出状态转移方程 (4)写出规划方程(包括边界条件),算法设计分析,(1)划分阶段,按照问题的时间或空间特征,把问题分为若干个阶段。 注意这若干个阶段一定要是有序的或者是可排序的(即无后向性) 否则问题就无法用动态规划求解。,算法设计分析,(2)选择状态,
41、将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。 当然,状态的选择要满足无后效性。,算法设计分析,(3)确定决策并写出状态转移方程,之所以把这两步放在一起,是因为决策和状态转移有着天然的联系: 状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。 所以,如果我们确定了决策,状态转移方程也就写出来了。 但事实上,我们常常是反过来做,根据相邻两段的各状态之间的关系来确定决策。,算法设计分析,(4)写出规划方程(包括边界条件),动态规划的基本方程是规划方程的通用形式化表达式。 一般说来,只要阶段、状态、决策和状态转移确定了,这一步还是比较简单的。 动态规划的主要难点在于理论上的设
42、计,一旦设计完成,实现部分就会非常简单。,算法设计分析,实际应用中的几个步骤,但是,实际应用当中经常不显式地按照上面步骤设计动态规划,而是按以下几个步骤进行: (1)分析最优解的性质,并刻划其结构特征。 (2)递归地定义最优值。 (3)以自底向上的方式或自顶向下的记忆化方法(备忘录法)计算出最优值。 (4)根据计算最优值时得到的信息,构造一个最优解。,算法设计分析,步骤(1)(3)是动态规划算法的基本步骤。 在只需要求出最优值的情形,步骤(4)可以省略 若需要求出问题的一个最优解,则必须执行步骤(4) 此时,在步骤(3)中计算最优值时,通常需记录更多的信息,以便在步骤(4)中,根据所记录的信息
43、,快速地构造出一个最优解。,算法设计分析,动态规划的适用条件,任何思想方法都有一定的局限性,超出了特定条件,它就失去了作用。 同样,动态规划也并不是万能的。 适用动态规划的问题必须满足: 最优化原理(最优子结构性质) 无后向性 子问题的重叠性,算法设计分析,(1)最优化原理(最优子结构性质),最优化原理可这样阐述:一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。 简而言之,一个最优化策略的子策略总是最优的。 一个问题满足最优化原理又称其具有最优子结构性质,算法设计分析,最优化原理是动态规划的基础 任何问题,如果失去了最优化原理的
44、支持,就不可能用动态规划方法计算。 根据最优化原理导出的动态规划基本方程是解决一切动态规划问题的基本方法。,算法设计分析,(2)无后向性,各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的决策 而只能通过当前的这个状态当前的状态去影响它的未来的发展 换句话说,每个状态都是过去历史的一个完整总结 这就是无后向性,又称为无后效性。,算法设计分析,(3)子问题的重叠性,动态规划算法的关键在于解决冗余,这是动态规划算法的根本目的。 动态规划实质上是一种以空间换时间的技术 它在实现的过程中,不得不存储产生过程中的各种状态,所以它的空间复杂度要大于其它的算法。
45、选择动态规划算法是因为动态规划算法在空间上可以承受 而搜索算法在时间上却无法承受,所以我们舍空间而取时间。,算法设计分析,能够用动态规划解决问题的显著特征,能够用动态规划解决的问题有一个显著特征:子问题的重叠性。 这个性质并不是动态规划适用的必要条件 但是如果该性质无法满足,动态规划算法同其他算法相比就不具备优势。,算法设计分析,无后效性,我们要求状态具有下面的性质: 如果给定某一阶段的状态,则在这一阶段以后过程的发展不受这阶段以前各段状态的影响,所有各阶段都确定时,整个过程也就确定了 换句话说,过程的每一次实现可以用一个状态序列表示,算法设计分析,在前面的例子中每阶段的状态是该线路的始点,确
46、定了这些点的序列,整个线路也就完全确定。 从某一阶段以后的线路开始,当这段的始点给定时,不受以前线路(所通过的点)的影响 状态的这个性质意味着过程的历史只能通过当前的状态去影响它的未来的发展,这个性质称为无后效性。,算法设计分析,最优性原理,作为整个过程的最优策略,它满足: 相对前面决策所形成的状态而言,余下的子策略必然构成“最优子策略”。 最优性原理实际上是要求问题的最优策略的子策略也是最优。 让我们通过对前面的例子再分析来具体说明这一点:从A到D,我们知道,最短路径是AB1C2D,这些点的选择构成了这个例子的最优策略 根据最优性原理,这个策略的每个子策略应是最优:AB1C2是A到C2的最短
47、路径,B1C2D也是B1到D的最短路径,算法设计分析,四 贪心算法,贪心算法的基本要求: 通过本章的学习,要求: 了解贪心法的基本思想 掌握贪婪算法的设计步骤 学会使用贪心算法分析和解决实际的问题 并对算法进行复杂性分析。,算法设计分析,主要内容,使用贪心算法分析和解决具体问题:活动安排问题最优装载问题哈夫曼编码单源最短路径最小生成树多机调度问题,算法设计分析,贪心算法的基本内容,贪心算法是这样一种算法,其特点是: 所做的选择都是目前最佳的 亦即,它期望通过所做的局部最优选择产生出一个全局最优解 这一章讨论可由贪心算法解决的最优化问题。,算法设计分析,适用于最优化问题的算法往住包含一系列步骤,
48、每一步都有一组选择 对许多最优化问题来说: 采用动态程序设计方法来决定最佳选择就有点“杀鸡用牛刀”了,只要采用另一些更简单有效的算法就行了。,算法设计分析,贪心算法对大多数优化问题来说能产生最优解,但也并不总是这样 贪心方法是一种很有效的方法,适用于一大类问题。 后面的章节中将给出许多可被视为贪心法的应用的算法,如最小生成树算法,Dijkstra的单源最短路径,以及贪心集合复合启发式等等 最小生成树是贪心法的一个经典例子。,算法设计分析,贪心算法的基本思想,贪心算法是通过做一系列的选择来给出某一问题的最优解的 对算法中的每一决策点,做一个当时(看起来像是)最佳的选择。 这种启发式策略并不是总能产生出最优解,但正像我们在活动选择问题中看到的那样,它常常能给出最优解 。,算法设计分析,适宜贪心策略解的问题的两个特点,对一个最优化问题,我们怎样才能知道用一个贪心算法来解它是否合适呢? 没有一个通用的方法。 适宜于用贪心策略来解的大多数问题都有两个特点:贪心选择性质和最优子结 构。,