动态规划

阅读 / 问答 / 标签

动态规划,极小值与变分法的区别

变分法前提是假设控制变量取值不受限制,控制变分是任意; 而实际控制变量一般是受限制的,极小值原理是变分法的延伸,是求解控制变量受限制的重要工具

迪杰斯特拉算法的本质是贪心还是动态规划?

一般意义上的贪心算法在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。Dijkstra算法显然是从整体最优考虑,求出的最短路径,一定是整体最优解,这是和一般意义上的贪心算法相悖的地方。而且Dijkstra算法符合动态规划的这一特性:待求解的问题分解为若干个子问题,前一子问题的解,为后一子问题的求解提供了有用的信息。在我看来,Dijkstra算法更接近动态规划。从维基百科也可以看到这样的说明:From a dynamic programming point of view, Dijkstra"s algorithm is a successive approximation scheme that solves the dynamic programming functional equation for the shortest path problem by the Reaching method.

是否能用动态规划算法求解的问题也能用贪心算法求解?

实际工程中动态规划往往很难实现,但是求解能得到全局最优。但是贪心算法虽然较易陷入局部最优,但是求解效率极高。若是决策量前后之间影响不是很大,且较大规模问题贪心法较好。

动态规划算法与贪心算法的异同

算法不同,都是一种递推算法。1、算法不同。贪心算法问题的最优解可以通过一系列局部最优的选择来达到,它仅在当前状态下做出最好选择,而动态规划的选择往往依赖相关子问题的解。2、都是一种递推算法。动态规划法与分治法和贪心法类似,它们都是将问题实例归纳为更小的、相似的子问题,并通过求解子问题产生一个全局最优解。

简述贪心,递归,动态规划,及分治算法之间的区别和联系

递归,简单的重复,计算量大。分治,解决问题独立,分开计算,如其名。动态规划算法通常以自底向上的方式解各子问题,贪心算法则通常以自顶向下的方式进行;动态规划能求出问题的最优解,贪心不能保证求出问题的最优解

迪杰斯特拉算法的本质是贪心还是动态规划?

一般意义上的贪心算法在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。Dijkstra算法显然是从整体最优考虑,求出的最短路径,一定是整体最优解,这是和一般意义上的贪心算法相悖的地方。而且Dijkstra算法符合动态规划的这一特性:待求解的问题分解为若干个子问题,前一子问题的解,为后一子问题的求解提供了有用的信息。在我看来,Dijkstra算法更接近动态规划。从维基百科也可以看到这样的说明:From a dynamic programming point of view, Dijkstra"s algorithm is a successive approximation scheme that solves the dynamic programming functional equation for the shortest path problem by the Reaching method.

动态规划和贪心算法的区别

动态规划和贪心算法的区别1、动态规划算法中,每步所做的选择往往依赖于相关子问题的解,因而只有在解出相关子问题时才能做出选择。而贪心算法,仅在当前状态下做出最好选择,即局部最优选择,然后再去解做出这个选择后产生的相应的子问题。2、动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常自顶向下的方式进行。共同点:两者都具有最优子结构性质 动态规划算法的基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。

大学课程《算法分析与设计》中动态规划和贪心算法的区别和联系?

对于,大学课程《算法分析与设计》中动态规划和贪心算法的区别和联系这个问题,首先要来聊聊他们的联系:1、都是一种推导算法;2、将它们分解为子问题求解,它们都需要有最优子结构。这两个特征师门的联系。然后,下面来说说他们的差别:贪心算法需要每一步的最优解必须包含前一步的最优解,前一步的最优解不保留;而动态规划是全局最优解必须包含一个局部最优解,而不是先前的局部最优解。因此,有必要记录所有以前的局部最优解。另一个不同是,贪心算法它如果所有子问题都被视为一棵树,贪婪从根开始,每次都遍历最优子树(通常这种“最优”基于当前情况下明显的“最优”);这样,就不需要知道一个节点的所有子树,所以它不能形成一个完整的树;而动态规划是从下到上,从叶到根构造子问题的解决方案。对于每个子树的根,找到下面每个叶子的值。最后,得到一棵完整的树,最后选择最优值作为自己的值来得到答案。可见,根据以上描述,贪心算法不能保证最终的解决方案是最好的,总体复杂度较低;动态规划的本质是穷举法,它能保证最优的结果和较高的复杂性。特别是对于0-1背包问题,它应该比较选择项目和不选择项目所导致的最终方案,然后做出最佳选择。由此衍生出许多重叠子问题,因此使用了动态规划。拓展资料:贪婪算法是指在解决问题时,它总是在当前做出最佳选择。也就是说,在不考虑全局优化的情况下,该算法在某种意义上获得了局部最优解。贪婪算法不能得到所有问题的全局最优解。关键是贪婪策略的选择。动态规划是运筹学的一个分支,是解决决策过程优化的过程。20世纪50年代初,美国数学家R·贝尔曼等人在研究多阶段决策过程的最优化问题时,提出了著名的最优化原理,建立了动态规划。动态规划在工程技术、经济、工业生产、军事和自动控制等领域有着广泛的应用,在背包问题、生产经营问题、资金管理问题、资源分配问题、最短路径问题和复杂系统可靠性问题上都取得了显著的成果。

动态规划和贪心算法的区别

如下:贪心法是每一步的最优解就是整体的最优解。0-1背包是属于动态规划,每一步的解不一定导致整体的最优解。对于你问“什么样的题用0-1背包问题作”就是需要你自己做题来体会了。如果全局的最优解可以用分布的最优解求出来,就用贪心,如果不是,就动态规划(0-1背包属于这类)。合并果子问题(可以自己去网上找哈~)就是典型的贪心,0-1背包问题就属于典型动态规划。贪心算法特性:贪心算法的关键不在于想到,而在于正确性的证明。要证明一个贪心算法是正确的,需要证明我们可以把一个最优解逐步转化为我们用贪心算法所得到的解。而解不会更差,从而证明贪心算法得到的解和最优解是一样好的(显然,最优解不可能更好)。而要证明一个贪心算法是错误的,只需要找到一个反例就可以了。动态规划和贪心算法都是一种递推算法,均有局部最优解来推导全局最优解,贪心算法:动态规划算法:贪心算法与动态规划。每次拿能拿的最大的,就是贪心。但是一定注意,贪心得到的并不是最优解,也就是说用贪心不一定是拿的最少的张数。

简述贪心,递归,动态规划,及分治算法之间的区别和联系

联系:都是问题求解之时的一种算法。区别:一、作用不同1、贪心算法:把子问题的解局部最优解合成原来解问题的一个解。2、递归算法:问题解法按递归算法实现。如Hanoi问题;数据的结构形式是按递归定义的。如二叉树、广义表等。3、动态规划:动态规划算法通常用于求解具有某种最优性质的问题。4、分治算法:可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。二、方法不同1、贪心算法:在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解。2、递归算法:通过重复将问题分解为同类的子问题而解决问题。3、动态规划:将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。4、分治算法:将一个规模为N的问题分解为K个规模较小的子问题。三、特点不同1、贪心算法:根据题意选取一种量度标准。2、递归算法:递归就是在过程或函数里调用自身。3、动态规划:虽然动态规划主要用于求解以时间划分阶段的动态过程的优化问题,但是一些与时间无关的静态规划(如线性规划、非线性规划),只要人为地引进时间因素,把它视为多阶段决策过程,也可以用动态规划方法方便地求解。4、分治算法:原问题可以分解为多个子问题;原问题在分解过程中,递归地求解子问题;在求解并得到各个子问题的解后。

C程序的动态规划是啥意思

动态规划是一种算法思想,可以找算法方面的书看看

关于动态规划算法,哪位可以讲一下自己心得体会?

正好我最近也在做动规的题。我来说说我觉得呢,动态规划和分治、递归、递推都差不多,都是把未知转化为已知来求。动态规划甚至就是一种递推!想一想求斐波那契数列的第 n 项。我们知道第 1 项是 1,第 2 项也是 1 。于是,接下来的问题就变成:根据第 1 项和第 2 项求第 3 项根据第 2 项和第 3 项求第 4 项……根据第 k-2 项和第 k-1 项求第 k 项……根据第 n-2 项和第 n-1 项求第 n 项这个时候,第 n 项就求出来啦!这就是递推的思路。其实,我觉得动态规划也是一样的。

帮我讲一下 动态规划

  动态规划的特点及其应用  安徽 张辰  目 录  (点击进入)  【关键词】  【摘要】  【正文】  §1动态规划的本质  §1.1多阶段决策问题  §1.2阶段与状态  §1.3决策和策略  §1.4最优化原理与无后效性  §1.5最优指标函数和规划方程  §2动态规划的设计与实现  §2.1动态规划的多样性  §2.2动态规划的模式性  §2.3动态规划的技巧性  §3动态规划与一些算法的比较  §3.1动态规划与递推  §3.2动态规划与搜索  §3.3动态规划与网络流  §4结语  【附录:部分试题与源程序】  1.“花店橱窗布置问题”试题  2.“钉子与小球”试题  3.例2“花店橱窗布置问题”方法1的源程序  4.例2“花店橱窗布置问题”方法2的源程序  5.例3“街道问题”的扩展  6.例4“mod 4最优路径问题”的源程序  7.例5“钉子与小球”的源程序  8.例6的源程序,“N个人的街道问题”  【参考文献】  【关键词】动态规划 阶段  【摘要】  动态规划是信息学竞赛中的常见算法,本文的主要内容就是分析它的特点。  文章的第一部分首先探究了动态规划的本质,因为动态规划的特点是由它的本质所决定的。第二部分从动态规划的设计和实现这两个角度分析了动态规划的多样性、模式性、技巧性这三个特点。第三部分将动态规划和递推、搜索、网络流这三个相关算法作了比较,从中探寻动态规划的一些更深层次的特点。  文章在分析动态规划的特点的同时,还根据这些特点分析了我们在解题中应该怎样利用这些特点,怎样运用动态规划。这对我们的解题实践有一定的指导意义。  【正文】  动态规划是编程解题的一种重要的手段,在如今的信息学竞赛中被应用得越来越普遍。最近几年的信息学竞赛,不分大小,几乎每次都要考察到这方面的内容。因此,如何更深入地了解动态规划,从而更为有效地运用这个解题的有力武器,是一个值得深入研究的问题。  要掌握动态规划的应用技巧,就要了解它的各方面的特点。首要的,是要深入洞悉动态规划的本质。  §1动态规划的本质  动态规划是在本世纪50年代初,为了解决一类多阶段决策问题而诞生的。那么,什么样的问题被称作多阶段决策问题呢?  §1.1多阶段决策问题  说到多阶段决策问题,人们很容易举出下面这个例子。  [例1] 多段图中的最短路径问题:在下图中找出从A1到D1的最短路径。  仔细观察这个图不难发现,它有一个特点。我们将图中的点分为四类(图中的A、B、C、D),那么图中所有的边都处于相邻的两类点之间,并且都从前一类点指向后一类点。这样,图中的边就被分成了三类(Auf0e0B、Buf0e0C、Cuf0e0D)。我们需要从每一类中选出一条边来,组成从A1到D1的一条路径,并且这条路径是所有这样的路径中的最短者。  从上面的这个例子中,我们可以大概地了解到什么是多阶段决策问题。更精确的定义如下:  多阶段决策过程,是指这样的一类特殊的活动过程,问题可以按时间顺序分解成若干相互联系的阶段,在每一个阶段都要做出决策,全部过程的决策是一个决策序列[1]。要使整个活动的总体效果达到最优的问题,称为多阶段决策问题。  从上述的定义中,我们可以明显地看出,这类问题有两个要素。一个是阶段,一个是决策。  §1.2阶段与状态  阶段:将所给问题的过程,按时间或空间特征分解成若干相互联系的阶段,以便按次序去求每阶段的解。常用字母k表示阶段变量。[1]  阶段是问题的属性。多阶段决策问题中通常存在着若干个阶段,如上面的例子,就有A、B、C、D这四个阶段。在一般情况下,阶段是和时间有关的;但是在很多问题(我的感觉,特别是信息学问题)中,阶段和时间是无关的。从阶段的定义中,可以看出阶段的两个特点,一是“相互联系”,二是“次序”。  阶段之间是怎样相互联系的?就是通过状态和状态转移。  状态:各阶段开始时的客观条件叫做状态。描述各阶段状态的变量称为状态变量,常用sk表示第k阶段的状态变量,状态变量sk的取值集合称为状态集合,用Sk表示。[1]  状态是阶段的属性。每个阶段通常包含若干个状态,用以描述问题发展到这个阶段时所处在的一种客观情况。在上面的例子中,行人从出发点A1走过两个阶段之后,可能出现的情况有三种,即处于C1、C2或C3点。那么第三个阶段就有三个状态S3={C1,C2,C3}。  每个阶段的状态都是由以前阶段的状态以某种方式“变化”而来,这种“变化”称为状态转移(暂不定义)。上例中C3点可以从B1点过来,也可以从B2点过来,从阶段2的B1或B2状态走到阶段3的C3状态就是状态转移。状态转移是导出状态的途径,也是联系各阶段的途径。  说到这里,可以提出应用动态规划的一个重要条件。那就是将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的发展,而只能通过当前的这个状态。换句话说,每个状态都是“过去历史的一个完整总结[1]”。这就是无后效性。对这个性质,下文还将会有解释。  §1.3决策和策略  上面的阶段与状态只是多阶段决策问题的一个方面的要素,下面是另一个方面的要素——决策。  决策:当各段的状态取定以后,就可以做出不同的决定,从而确定下一阶段的状态,这种决定称为决策。表示决策的变量,称为决策变量,常用uk(sk)表示第k阶段当状态为sk时的决策变量。在实际问题中,决策变量的取值往往限制在一定范围内,我们称此范围为允许决策集合。常用Dk(sk)表示第k阶段从状态sk出发的允许决策集合。显然有uk(sk) uf0ceDk(sk)。[1]  决策是问题的解的属性。决策的目的就是“确定下一阶段的状态”,还是回到上例,从阶段2的B1状态出发有三条路,也就是三个决策,分别导向阶段3的C1、C2、C3三个状态,即D2(B1)={C1,C2,C3}。  有了决策,我们可以定义状态转移:动态规划中本阶段的状态往往是上一阶段和上一阶段的决策结果,由第k段的状态sk和本阶段的决策uk确定第k+1段的状态sk+1的过程叫状态转移。状态转移规律的形式化表示sk+1=Tk(sk,uk)称为状态转移方程。  这样看来,似乎决策和状态转移有着某种联系。我的理解,状态转移是决策的目的,决策是状态转移的途径。  各段决策确定后,整个问题的决策序列就构成一个策略,用p1,n={u1(s1),u2(s2),…, un(sn)}表示。对每个实际问题,可供选择的策略有一定范围,称为允许策略集合,记作P1,n,使整个问题达到最有效果的策略就是最优策略。[1]  说到这里,又可以提出运用动态规划的一个前提。即这个过程的最优策略应具有这样的性质:无论初始状态及初始决策如何,对于先前决策所形成的状态而言,其以后的所有决策应构成最优策略[1]。这就是最优化原理。简言之,就是“最优策略的子策略也是最优策略”。  §1.4最优化原理与无后效性  这里,我把最优化原理定位在“运用动态规划的前提”。这是因为,是否符合最优化原理是一个问题的本质特征。对于不满足最优化原理的一个多阶段决策问题,整体上的最优策略p1,n同任何一个阶段k上的决策uk或任何一组阶段k1…k2上的子策略pk1,k2都不存在任何关系。如果要对这样的问题动态规划的话,我们从一开始所作的划分阶段等努力都将是徒劳的。  而我把无后效性定位在“应用动态规划的条件”,是因为动态规划是按次序去求每阶段的解,如果一个问题有后效性,那么这样的次序便是不合理的。但是,我们可以通过重新划分阶段,重新选定状态,或者增加状态变量的个数等手段,来是问题满足无后效性这个条件。说到底,还是要确定一个“序”。  在信息学的多阶段决策问题中,绝大部分都是能够满足最优化原理的,但它们往往会在后效性这一点上来设置障碍。所以在解题过程中,我们会特别关心“序”。对于有序的问题,就会考虑到动态规划;对于无序的问题,也会想方设法来使其有序。  §1.5最优指标函数和规划方程  最优指标函数:用于衡量所选定策略优劣的数量指标称为指标函数,最优指标函数记为fk(sk),它表示从第k段状态sk采用最优策略p*k,n到过程终止时的最佳效益值[1]。  最优指标函数其实就是我们真正关心的问题的解。在上面的例子中,f2(B1)就表示从B1点到终点D1点的最短路径长度。我们求解的最终目标就是f1(A1)。  最优指标函数的求法一般是一个从目标状态出发的递推公式,称为规划方程:  其中sk是第k段的某个状态,uk是从sk出发的允许决策集合Dk(sk)中的一个决策,Tk(sk,uk)是由sk和uk所导出的第k+1段的某个状态sk+1,g(x,uk)是定义在数值x和决策uk上的一个函数,而函数opt表示最优化,根据具体问题分别表为max或min。  ,称为边界条件。  上例中的规划方程就是:  边界条件为  这里是一种从目标状态往回推的逆序求法,适用于目标状态确定的问题。在我们的信息学问题中,也有很多有着确定的初始状态。当然,对于初始状态确定的问题,我们也可以采用从初始状态出发往前推的顺序求法。事实上,这种方法对我们来说要更为直观、更易设计一些,从而更多地出现在我们的解题过程中。  我们本节所讨论的这些理论虽然不是本文的主旨,但是却对下面要说的动态规划的特点起着基础性的作用。  §2动态规划的设计与实现  上面我们讨论了动态规划的一些理论,本节我们将通过几个例子中,动态规划的设计与实现,来了解动态规划的一些特点。  §2.1动态规划的多样性  [例2] 花店橱窗布置问题(IOI99)试题见附录  本题虽然是本届IOI中较为简单的一题,但其中大有文章可作。说它简单,是因为它有序,因此我们一眼便可看出这题应该用动态规划来解决。但是,如何动态规划呢?如何划分阶段,又如何选择状态呢?  <方法1>以花束的数目来划分阶段。在这里,阶段变量k表示的就是要布置的花束数目(前k束花),状态变量sk表示第k束花所在的花瓶。而对于每一个状态sk,决策就是第k-1束花应该放在哪个花瓶,用uk表示。最优指标函数fk(sk)表示前k束花,其中第k束插在第sk个花瓶中,所能取得的最大美学值。  状态转移方程为  规划方程为  (其中A(i,j)是花束i插在花瓶j中的美学值)  边界条件 (V是花瓶总数,事实上这是一个虚拟的边界)  <方法2>以花瓶的数目来划分阶段。在这里阶段变量k表示的是要占用的花瓶数目(前k个花瓶),状态变量sk表示前k个花瓶中放了多少花。而对于任意一个状态sk,决策就是第sk束花是否放在第k个花瓶中,用变量uk=1或0来表示。最优指标函数fk(sk)表示前k个花瓶中插了sk束花,所能取得的最大美学值。  状态转移方程为  规划方程为  边界条件为  两种划分阶段的方法,引出了两种状态表示法,两种规划方式,但是却都成功地解决了问题。只不过因为决策的选择有多有少,所以算法的时间复杂度也就不同。[2]  这个例子具有很大的普遍性。有很多的多阶段决策问题都有着不止一种的阶段划分方法,因而往往就有不止一种的规划方法。有时各种方法所产生的效果是差不多的,但更多的时候,就像我们的例子一样,两种方法会在某个方面有些区别。  所以,在用动态规划解题的时候,可以多想一想是否有其它的解法。对于不同的解法,要注意比较,好的算法好在哪里,差一点的算法差在哪里。从各种不同算法的比较中,我们可以更深刻地领会动态规划的构思技巧。  §2.2动态规划的模式性  这个可能做过动态规划的人都有体会,从我们上面对动态规划的分析也可以看出来。动态规划的设计都有着一定的模式,一般要经历以下几个步骤。  划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。注意这若干个阶段一定要是有序的或者是可排序的,否则问题就无法求解。  选择状态:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。  确定决策并写出状态转移方程:之所以把这两步放在一起,是因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以,如果我们确定了决策,状态转移方程也就写出来了。但事实上,我们常常是反过来做,根据相邻两段的各状态之间的关系来确定决策。  写出规划方程(包括边界条件):在第一部分中,我们已经给出了规划方程的通用形式化表达式。一般说来,只要阶段、状态、决策和状态转移确定了,这一步还是比较简单的。  动态规划的主要难点在于理论上的设计,一旦设计完成,实现部分就会非常简单。大体上的框架如下:  对f1(s1)初始化(边界条件)  for kuf0df2 to n(这里以顺序求解为例)  对每一个skuf0ceSk  fk(sk)uf0df一个极值(∞或-∞)  对每一个uk(sk)uf0ceDk(sk)  sk-1uf0dfTk(sk,uk)  tuf0dfg(fk-1(sk-1),uk)  y t比fk(sk)更优 n  fk(sk)uf0dft  输出fn(sn)  这个N-S图虽然不能代表全部,但足可以概括大多数。少数的一些特殊的动态规划,其实现的原理也是类似,可以类比出来。我们到现在对动态规划的分析,主要是在理论上、设计上,原因也就在此。  掌握了动态规划的模式性,我们在用动态规划解题时就可以把主要的精力放在理论上的设计。一旦设计成熟,问题也就基本上解决了。而且在设计算法时也可以按部就班地来。  但是“物极必反”,太过拘泥于模式就会限制我们的思维,扼杀优良算法思想的产生。我们在解题时,不妨发挥一下创造性,去突破动态规划的实现模式,这样往往会收到意想不到的效果。[3]  §2.3动态规划的技巧性  上面我们所说的动态规划的模式性,主要指的是实现方面。而在设计方面,虽然它较为严格的步骤性,但是它的设计思想却是没有一定的规律可循的。这就需要我们不断地在实践当中去掌握动态规划的技巧,下面仅就一个例子谈一点我自己的体会。  [例3] 街道问题:在下图中找出从左下角到右上角的最短路径,每步只能向右方或上方走。  这是一道简单而又典型的动态规划题,许多介绍动态规划的书与文章中都拿它来做例子。通常,书上的解答是这样的:  按照图中的虚线来划分阶段,即阶段变量k表示走过的步数,而状态变量sk表示当前处于这一阶段上的哪一点(各点所对应的阶段和状态已经用ks在地图上标明)。这时的模型实际上已经转化成了一个特殊的多段图。用决策变量uk=0表示向右走,uk=1表示向上走,则状态转移方程如下:  (这里的row是地图竖直方向的行数)  我们看到,这个状态转移方程需要根据k的取值分两种情况讨论,显得非常麻烦。相应的,把它代入规划方程而付诸实现时,算法也很繁。因而我们在实现时,一般是不会这么做的,而代之以下面方法:  将地图中的点规则地编号如上,得到的规划方程如下:  (这里Distance表示相邻两点间的边长)  这样做确实要比上面的方法简单多了,但是它已经破坏了动态规划的本来面目,而不存在明确的阶段特征了。如果说这种方法是以地图中的行(A、B、C、D)来划分阶段的话,那么它的“状态转移”就不全是在两个阶段之间进行的了。  也许这没什么大不了的,因为实践比理论更有说服力。但是,如果我们把题目扩展一下:在地图中找出从左下角到右上角的两条路径,两条路径中的任何一条边都不能重叠,并且要求两条路径的总长度最短。这时,再用这种“简单”的方法就不太好办了。  如果非得套用这种方法的话,则最优指标函数就需要有四维的下标,并且难以处理两条路径“不能重叠”的问题。  而我们回到原先“标准”的动态规划法,就会发现这个问题很好解决,只需要加一维状态变量就成了。即用sk=(ak,bk)分别表示两条路径走到阶段k时所处的位置,相应的,决策变量也增加一维,用uk=(xk,yk)分别表示两条路径的行走方向。状态转移时将两条路径分别考虑:  在写规划方程时,只要对两条路径走到同一个点的情况稍微处理一下,减少可选的决策个数:  从这个例子中可以总结出设计动态规划算法的一个技巧:状态转移一般是在相邻的两个阶段之间(有时也可以在不相邻的两个阶段间),但是尽量不要在同一个阶段内进行。  动态规划是一种很灵活的解题方法,在动态规划算法的设计中,类似的技巧还有很多。要掌握动态规划的技巧,有两条途径:一是要深刻理解动态规划的本质,这也是我们为什么一开始就探讨它的本质的原因;二是要多实践,不但要多解题,还要学会从解题中探寻规律,总结技巧。  §3动态规划与一些算法的比较  动态规划作为诸多解题方法中的一种,必然和其他一些算法有着诸多联系。从这些联系中,我们也可以看出动态规划的一些特点。  §3.1动态规划与递推  ——动态规划是最优化算法  由于动态规划的“名气”如此之大,以至于很多人甚至一些资料书上都往往把一种与动态规划十分相似的算法,当作是动态规划。这种算法就是递推。实际上,这两种算法还是很容易区分的。  按解题的目标来分,信息学试题主要分四类:判定性问题、构造性问题、计数问题和最优化问题。我们在竞赛中碰到的大多是最优化问题,而动态规划正是解决最优化问题的有力武器,因此动态规划在竞赛中的地位日益提高。而递推法在处理判定性问题和计数问题方面也是一把利器。下面分别就两个例子,谈一下递推法和动态规划在这两个方面的联系。  [例4] mod 4 最优路径问题:在下图中找出从第1点到第4点的一条路径,要求路径长度mod 4的余数最小。  这个图是一个多段图,而且是一个特殊的多段图。虽然这个图的形式比一般的多段图要简单,但是这个最优路径问题却不能用动态规划来做。因为一条从第1点到第4点的最优路径,在它走到第2点、第3点时,路径长度mod 4的余数不一定是最小,也就是说最优策略的子策略不一定最优——这个问题不满足最优化原理。  但是我们可以把它转换成判定性问题,用递推法来解决。判断从第1点到第k点的长度mod 4为sk的路径是否存在,用fk(sk)来表示,则递推公式如下:  (边界条件)  (这里lenk,i表示从第k-1点到第k点之间的第i条边的长度,方括号表示“或(or)”运算)  最后的结果就是可以使f4(s4)值为真的最小的s4值。  这个递推法的递推公式和动态规划的规划方程非常相似,我们在这里借用了动态规划的符号也就是为了更清楚地显示这一点。其实它们的思想也是非常相像的,可以说是递推法借用了动态规划的思想解决了动态规划不能解决的问题。  有的多阶段决策问题(像这一题的阶段特征就很明显),由于不能满足最优化原理等使用动态规划的先决条件,而无法应用动态规划。在这时可以将最优指标函数的值当作“状态”放到下标中去,从而变最优化问题为判定性问题,再借用动态规划的思想,用递推法来解决问题。  [例5] 钉子与小球(NOI99)试题见附录  这个题目一看就不觉让人想起一道经典的动态规划题。下面先让我们回顾一下这个问题。  数字三角形(IOI94)在下图中求从顶至低某处的一条路径,使该路径所经过的数字的总和最大,每一步只能向左下或右下走。  7  3 8  8 1 0  2 7 4 4  4 5 2 6 5  在这个问题中,我们按走过的行数来划分阶段,以走到每一行时所在的位置来作为状态,决策就是向左下走(用0表示)或向右下走(用1表示)。  状态转移方程:  规划方程:  边界条件:  这是一个比较简单的最优化问题,我们还可以把这个问题改成一个更加简单的整数统计问题:求顶点到每一点的路径总数。把这个总数用fk(sk)表示,那么递推公式就是:  在这里,虽然求和公式只有两项,但我们仍然用∑的形式表示,就是为了突出这个递推公式和上面的规划方程的相似之处。这两个公式的边界条件都是一模一样的。  再回到我们上面的“钉子与小球”问题,这是一个概率统计问题。我们继续沿用上面的思想,用fk(sk)表示小球落到第k行第sk个钉子上的概率,则递推公式如下:  (这里函数Existk(sk)表示第k行第sk个钉子是否存在,存在则取1,不存在则取0)  边界条件  可以看出这个公式较之上面的两个式子虽然略有变化,但是其基本思想还是类似的。在解这个问题的过程中,我们再次运用了动态规划的思想。  一般说来,很多最优化问题都有着对应的计数问题;反过来,很多计数问题也有着对应的最优化问题。因此,我们在遇到这两类问题时,不妨多联系、多发展,举一反三,从比较中更深入地理解动态规划的思想。  其实递推和动态规划这两种方法的思想本来就很相似,也不必说是谁借用了谁的思想。关键在于我们要掌握这种思想,这样我们无论在用动态规划法解最优化问题,或是在用递推法解判定型、计数问题时,都能得心应手、游刃有余了。  §3.2动态规划与搜索  ——动态规划是高效率、高消费算法  同样是解决最优化问题,有的题目我们采用动态规划,而有的题目我们则需要用搜索。这其中有没有什么规则呢?  我们知道,撇开时空效率的因素不谈,在解决最优化问题的算法中,搜索可以说是“万能”的。所以动态规划可以解决的问题,搜索也一定可以解决。  把一个动态规划算法改写成搜索是非常方便的,状态转移方程、规划方程以及边界条件都可以直接“移植”,所不同的只是求解顺序。动态规划是自底向上的递推求解,而搜索则是自顶向下的递归求解(这里指深度搜索,宽度搜索类似)。  反过来,我们也可以把搜索算法改写成动态规划。状态空间搜索实际上是对隐式图中的点进行枚举,这种枚举是自顶向下的。如果把枚举的顺序反过来,变成自底向上,那么就成了动态规划。(当然这里有个条件,即隐式图中的点是可排序的,详见下一节。)  正因为动态规划和搜索有着求解顺序上的不同,这也造成了它们时间效率上的差别。在搜索中,往往会出现下面的情况:  对于上图(a)这样几个状态构成的一个隐式图,用搜索算法就会出现重复,如上图(b)所示,状态C2被搜索了两次。在深度搜索中,这样的重复会引起以C2为根整个的整个子搜索树的重复搜索;在宽度搜索中,虽然这样的重复可以立即被排除,但是其时间代价也是不小的。而动态规划就没有这个问题,如上图(c)所示。  一般说来,动态规划算法在时间效率上的优势是搜索无法比拟的。(当然对于某些题目,根本不会出现状态的重复,这样搜索和动态规划的速度就没有差别了。)而从理论上讲,任何拓扑有序(现实中这个条件常常可以满足)的隐式图中的搜索算法都可以改写成动态规划。但事实上,在很多情况下我们仍然不得不采用搜索算法。那么,动态规划算法在实现上还有什么障碍吗?  考虑上图(a)所示的隐式图,其中存在两个从初始状态无法达到的状态。在搜索算法中,这样的两个状态就不被考虑了,如上图(b)所示。但是动态规划由于是自底向上求解,所以就无法估计到这一点,因而遍历了全部的状态,如上图(c)所示。  一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态。更重要的事搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多。  如何协调好动态规划的高效率与高消费之间的矛盾呢?有一种折衷的办法就是记忆化算法。记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来,以后再次遇到这个状态的时候,就不必重新求解了。这种方法综合了搜索和动态规划两方面的优点,因而还是很有实用价值的。  §3.3动态规划与网络流  ——动态规划是易设计易实现算法  由于图的关系复杂而无序,一般难以呈现阶段特征(除了特殊的图如多段图,或特殊的分段方法如Floyd),因此动态规划在图论中的应用不多。但有一类图,它的点却是有序的,这就是有向无环图。  在有向无环图中,我们可以对点进行拓扑排序,使其体现出有序的特征,从而据此划分阶段。在有向无还图中求最短路径的算法[4],已经体现出了简单的动态规划思想。但动态规划在图论中还有更有价值的应用。下面先看一个例子。  [例6] N个人的街道问题:在街道问题(参见例3)中,若有N个人要从左下角走向右上角,要求他们走过的边的总长度最大。当然,这里每个人也只能向右或向上走。下面是一个样例,左图是从出发地到目的地的三条路径,右图是他们所走过的边,这些边的总长度为5 + 4 + 3 + 6 + 3 + 3 + 5 + 8 + 8 + 7 + 4 + 5 + 9 + 5 + 3 = 78(不一定是最大)。  这个题目是对街道问题的又一次扩展。仿照街道问题的解题方法,我们仍然可以用动态规划来解决本题。不过这一次是N个人同时走,状态变量也就需要用N维来表示,。相应的,决策变量也要变成N维,uk=(uk,1,uk,2,…,uk,N)。状态转移方程不需要做什么改动:  在写规划方程时,需要注意在第k阶段,N条路径所走过的边的总长度的计算,在这里我就用gk(sk,uk)来表示了:  边界条件为  可见将原来的动态规划算法移植到这个问题上来,在理论上还是完全可行的。但是,现在的这个动态规划算法的时空复杂度已经是关于N的指数函数,只要N稍微大一点,这个算法就不可能实现了。  下面我们换一个思路,将N条路径看成是网络中一个流量为N的流,这样求解的目标就是使这个流的费用最大。但是本题又不同于一般的费用流问题,在每一条边e上的流费用并不是流量和边权的乘积 ,而是用下式计算:  为了使经典的费用流算法适用于本题,我们需要将模型稍微转化一下:  如图,将每条边拆成两条。拆开后一条边上有权,但是容量限制为1;另一条边没有容量限制,但是流过这条边就不能计算费用了。这样我们就把问题转化成了一个标准的最大费用固定流问题。  这个算法可以套用经典的最小费用最大流算法,在此就不细说了。(参见附录中的源程序)  这个例题是我仿照IOI97的“障碍物探测器”一题[6]编出来的。“障碍物探

smith waterman算法中的动态规划中怎么将所有的路径显示出来

function fib(n) var previousFib := 0, currentFib := 1 if n = 0 return 0 else if n = 1 return 1 repeat n-1 times var newFib := previousFib + currentFib previousFib := currentFib currentFib := newFib return currentFib在这两个例子,我们都只计算fib(2)一次,然后用它来计算fib(3)和fib(4),而不是每次都重新计算。2. 一种平衡的0-1矩阵考虑n*n矩阵的赋值问题:只能赋0和1,n为偶数,使每一行和列均含n/2个0及n/2个1。例如,当n=4时,两种可能的方案是:+ - - - - + + - - - - +| 0 1 0 1 | | 0 0 1 1 || 1 0 1 0 | | 0 0 1 1 || 0 1 0 1 | | 1 1 0 0 || 1 0 1 0 | | 1 1 0 0 |+ - - - - + + - - - - +问:对于给定n,共有多少种不同的赋值方案。至少有三种可能的算法来解决这一问题:穷举法(brute force)、回溯法(backtracking)及动态规划(dynamic programming)。穷举法列举所有赋值方案,并逐一找出满足平衡条件的方案。由于共有C(n, n/2)^n种方案(在一行中,含n/2个0及n/2个1的组合数为C(n,n/2),相当于从n个位置中选取n/2个位置置0,剩下的自然是1),当n=6时,穷举法就已经几乎不可行了。回溯法先将矩阵中部分元素置为0或1,然后检查每一行和列中未被赋值的元素并赋值,使其满足每一行和列中0和1的数量均为n/2。回溯法比穷举法更加巧妙一些,但仍需遍历所有解才能确定解的数目,可以看到,当n=8时,该题解的数目已经高达116963796250。动态规划则无需遍历所有解便可确定解的数目(意思是划分子问题后,可有效避免若干子问题的重复计算)。通过动态规划求解该问题出乎意料的简单。考虑每一行恰含n/2个0和n/2个1的k*n(1<=k<=n)的子矩阵,函数f根据每一行的可能的赋值映射为一个向量,每个向量由n个整数对构成。向量每一列对应的一个整数对中的两个整数分别表示该列上该行以下已经放置的0和1的数量。该问题即转化为寻找f((n/2,n/2),(n/2,n/2),...,(n/2,n/2))(具有n个参数或者说是一个含n个元素的向量)的值。其子问题的构造过程如下:1) 最上面一行(第k行)具有C(n, n/2)种赋值;2) 根据最上面一行中每一列的赋值情况(为0或1),将其对应整数对中相应的元素值减1;3) 如果任一整数对中的任一元素为负,则该赋值非法,不能成为正确解;4) 否则,完成对k*n的子矩阵中最上面一行的赋值,取k=k-1,计算剩余的(k-1)*n的子矩阵的赋值;5) 基本情况是一个1*n的细小的子问题,此时,该子问题的解的数量为0或1,取决于其向量是否是n/2个(0, 1)和n/2个(1, 0)的排列。例如,在上面给出的两种方案中,向量序列为:((2, 2) (2, 2) (2, 2) (2, 2)) ((2, 2) (2, 2) (2, 2) (2, 2)) k = 4 0 1 0 1 0 0 1 1((1, 2) (2, 1) (1, 2) (2, 1)) ((1, 2) (1, 2) (2, 1) (2, 1)) k = 3 1 0 1 0 0 0 1 1((1, 1) (1, 1) (1, 1) (1, 1)) ((0, 2) (0, 2) (2, 0) (2, 0)) k = 2 0 1 0 1 1 1 0 0((0, 1) (1, 0) (0, 1) (1, 0)) ((0, 1) (0, 1) (1, 0) (1, 0)) k = 1 1 0 1 0 1 1 0 0((0, 0) (0, 0) (0, 0) (0, 0)) ((0, 0) (0, 0), (0, 0) (0, 0))动态规划在此的意义在于避免了相同f的重复计算,更进一步的,上面着色的两个f,虽然对应向量不同,但f的值是相同的,想想为什么吧:D。该问题解的数量(序列a058527在OEIS)是1, 2, 90, 297200, 116963796250, 6736218287430460752, ...下面的外部链接中包含回溯法的Perl源代码实现,以及动态规划法的MAPLE和C语言的实现。3. 棋盘考虑n*n的棋盘及成本函数C(i,j),该函数返回方格(i,j)相关的成本。以5*5的棋盘为例:5 | 6 7 4 7 84 | 7 6 1 1 43 | 3 5 7 8 22 | 2 6 7 0 21 | 7 3 5 6 1- + - - - - -| 1 2 3 4 5可以看到:C(1,3)=5从棋盘的任一方格的第一阶(即行)开始,寻找到达最后一阶的最短路径(使所有经过的方格的成本之和最小),假定只允许向左对角、右对角或垂直移动一格。5 |4 |3 |2 | x x x1 | o- + - - - - -| 1 2 3 4 5该问题展示了最优子结构。即整个问题的全局解依赖于子问题的解。定义函数q(i,j),令:q(i,j)表示到达方格(i,j)的最低成本。如果我们可以求出第n阶所有方格的q(i,j)值,取其最小值并逆向该路径即可得到最短路径。记q(i,j)为方格(i,j)至其下三个方格((i-1,j-1)、(i-1,j)、(i-1,j+1))最低成本与c(i,j)之和,例如:5 |4 | A3 | B C D2 |1 |- + - - - - -| 1 2 3 4 5q(A) = min(q(B),q(C),q(D)) + c(A)定义q(i,j)的一般形式:|- inf. j<1 or j>nq(i,j) = -+- c(i,j) i=1 |- min(q(i-1,j-1),q(i-1,j),q(i-1,j+1))+c(i,j) otherwise.方程的第一行是为了保证递归可以退出(处理边界时只需调用一次递归函数)。第二行是第一阶的取值,作为计算的起点。第三行的递归是算法的重要组成部分,与例子A、B、C、D类似。从该定义我们可以直接给出计算q(i,j)的简单的递归代码。在下面的伪代码中,n表示棋盘的维数,C(i,j)是成本函数,min()返回一组数的最小值:function minCost(i, j) if j < 1 or j > n return infinity else if i = 1 return c(i,j) else return min(minCost(i-1,j-1),minCost(i-1,j),minCost(i-1,j+1))+c(i,j)需要指出的是,minCost只计算路径成本,并不是最终的实际路径,二者相去不远。与Fibonacci数相似,由于花费大量时间重复计算相同的最短路径,这一方式慢的恐怖。不过,如果采用自下而上法,使用二维数组q[i,j]代替函数minCost,将使计算过程快得多。我们为什么要这样做呢?选择保存值显然比使用函数重复计算相同路径要简单的多。我们还需要知道实际路径。路径问题,我们可以通过另一个前任数组p[i,j]解决。这个数组用于描述路径,代码如下:function computeShortestPathArrays() for x from 1 to n q[1, x] := c(1, x) for y from 1 to n q[y, 0] := infinity q[y, n + 1] := infinity for y from 2 to n for x from 1 to n m := min(q[y-1, x-1], q[y-1, x], q[y-1, x+1]) q[y, x] := m + c(y, x) if m = q[y-1, x-1] p[y, x] := -1 else if m = q[y-1, x] p[y, x] := 0 else p[y, x] := 1剩下的求最小值和输出就比较简单了:function computeShortestPath() computeShortestPathArrays() minIndex := 1 min := q[n, 1] for i from 2 to n if q[n, i] < min minIndex := i min := q[n, i] printPath(n, minIndex)function printPath(y, x) print(x) print("<-")if y = 2 print(x + p[y, x]) else printPath(y-1, x + p[y, x])

生物学中常用的两种动态规划算法

动态规划算法(Dynamic Programming Algorithm)是一种计算方法,它的主要思路是把一个问题分成若干个小问题来解决在生物学中应用的两种动态规划算法:Needleman-Wunsch算法(全局比对)和Smith-Waterman算法(局部比对)(1)全局序列比对:1)两条序列可以在一个x- 和y-轴的矩阵中得到比对;2)如果序列一致,则可以得到一条通过对角线的路径;3)寻找最佳的次路径,然后将它们加起来得到最好的得分,这包括:需要时插入空隙(gap)允许保守替代选择打分系统(简单的或复杂的)Needleman-Wunsch算法可以保证得到最佳的比对(2)局部序列比对:局部比对的目标是寻找两序列最优比对区(子序列),不需要延伸到序列的两端;局部比对是数据库搜索是最常用的算法,在寻找序列之间的结构域时相当有用。 1)Smith-Waterman 算法1. 设置一个矩阵,大小为(m+1, n+1)2. 矩阵中的值必须不小于0。3. 矩阵中的每个单元格的分值S是以下四者中的最大值:1. 算法的目的是寻找矩阵中的最大值,这代表了比对中的结尾处(羧基端)。2. 回溯过程从最大值的位置开始,沿着对角线向上向左直到碰到一个零分值的单元格。3. 算法需要的一个条件是随机匹配的期望分值为负,保证不相关的长序列不能得到高分值(大多打分矩阵满足此条)