ImageVerifierCode 换一换
格式:DOCX , 页数:8 ,大小:19.20KB ,
资源ID:6305208      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6305208.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(动态规划算法.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

动态规划算法.docx

1、动态规划算法动态规划一般也只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似)。简单地说,问题能够分解成子问题来解决。动态规划算法分以下4个步骤:1.描述最优解的结构2.递归定义最优解的值3.按自底向上的方式计算最优解的值 /此3步构成动态规划解的基础。4.由计算出的结果构造一个最优解。 /此步如果只要求计算最优解的值时,可省略。好,接下来,咱们讨论适合采用动态规划方法的最优化问题的俩个要素:最优子结构性质,和子问题重叠性质。一、最优子结构。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子

2、结构性质(即满足最优化原理)。意思就是,总问题包含很多歌子问题,而这些子问题的解也是最优的。二、重叠子问题。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。ok,咱们马上进入面试题第56题的求解,即运用经典的动态规划算法:56.最长公共子序列。题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串

3、二的子串。注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子串,则输出它们的长度4,并打印任意一个子串。分析:求最长公共子串(Longest Common Subsequence, LCS)是一道非常经典的动态规划题,因此一些重视算法的公司像MicroStrategy都把它当作面试题。步骤一、描述一个最长公共子序列先介绍LCS问题的性质:记Xm=x0, x1,xm-1和Yn=y0,y1,yn-1为两个字符串,并设

4、Zk=z0,z1,zk-1是X和Y的任意一个LCS,则可得出3条性质:1. 如果xm-1=yn-1,那么zk-1=xm-1=yn-1,并且Zk-1是Xm-1和Yn-1的一个LCS;2. 如果xm-1yn-1,那么当zk-1xm-1时,Z是Xm-1和Y的LCS;3. 如果xm-1yn-1,那么当zk-1yn-1时,Z是X和Yn-1的LCS;下面简单证明一下由上述相应条件得出的这些性质:1. 如果zk-1xm-1,那么我们可以把xm-1(yn-1)加到Z中得到Z,这样就得到X和Y的一个长度为k+1的公共子串Z。这就与长度为k的Z是X和Y的LCS相矛盾了。因此一定有zk-1=xm-1=yn-1。既然

5、zk-1=xm-1=yn-1,那如果我们删除zk-1(xm-1、yn-1)得到的Zk-1,Xm-1和Yn-1,显然Zk-1是Xm-1和Yn-1的一个公共子串,现在我们证明Zk-1是Xm-1和Yn-1的LCS。用反证法不难证明。假设有Xm-1和Yn-1有一个长度超过k-1的公共子串W,那么我们把加到W中得到W,那W就是X和Y的公共子串,并且长度超过k,这就和已知条件相矛盾了。2. 还是用反证法证明。假设Z不是Xm-1和Y的LCS,则存在一个长度超过k的W是Xm-1和Y的LCS,那W肯定也X和Y的公共子串,而已知条件中X和Y的公共子串的最大长度为k。矛盾。3. 证明同2。步骤二、一个递归解根据上面

6、的性质,我们可以得出如下的思路:求两字符串Xm=x0, x1,xm-1和Yn=y0,y1,yn-1的LCS,如果xm-1=yn-1,那么只需求得Xm-1和Yn-1的LCS,并在其后添加xm-1(yn-1)即可(上述性质1);如果xm-1yn-1,我们分别求得Xm-1和Y的LCS和Yn-1和X的LCS,并且这两个LCS中较长的一个为X和Y的LCS(上述性质2、3)。根据上述结论,可得到以下公式,如果我们记字符串Xi和Yj的LCS的长度为ci,j,我们可以递归地求ci,j: / 0 if i0 or j=0 and xi=xj / max(ci,j-1,ci-1,j if i,j=0 and xi

7、xj上面的公式用递归函数不难求得。自然想到Fibonacci第n项(本微软等100题系列V0.1版第19题)问题的求解中可知,直接递归会有很多重复计算,所以,我们用从底向上循环求解的思路效率更高。为了能够采用循环求解的思路,我们用一个矩阵(参考下文文末代码中的LCS_length)保存下来当前已经计算好了的ci,j,当后面的计算需要这些数据时就可以直接从矩阵读取。另外,求取ci,j可以从ci-1,j-1 、ci,j-1或者ci-1,j三个方向计算得到,相当于在矩阵LCS_length中是从ci-1,j-1,ci,j-1或者ci-1,j的某一个各自移动到ci,j,因此在矩阵中有三种不同的移动方向

8、:向左、向上和向左上方,其中只有向左上方移动时才表明找到LCS中的一个字符。于是我们需要用另外一个矩阵(参考下文文末代码中的LCS_direction)保存移动的方向。步骤三,计算LCS的长度LCS-LENGTH(X, Y)1 m lengthX2 n lengthY3 for i 1 to m4 do ci, 0 05 for j 0 to n6 do c0, j 07 for i 1 to m8 do for j 1 to n9 do if xi = yj10 then ci, j ci - 1, j - 1 + 111 bi, j 12 else if ci - 1, j ci, j -

9、 113 then ci, j ci - 1, j14 bi, j 15 else ci, j ci, j - 116 bi, j 17 return c and b此过程LCS-LENGTH以俩个序列X = x1, x2, ., xm 和 Y = y1, y2, ., yn为输入。它把ci,j值填入一个按行计算表项的表c0 m, 0 n 中, 它还维护b1 m, 1 n 以简化最优解的构造。从直觉上看,bi, j 指向一个表项,这个表项对应于与在计算 ci, j时所选择的最优子问题的解是相同的。该程序返回表中 b and c , cm, n 包含X和Y的一个LCS的长度。步骤四,构造一个LC

10、S,PRINT-LCS(b, X, i, j)1 if i = 0 or j = 02 then return3 if bi, j = 4 then PRINT-LCS(b, X, i - 1, j - 1)5 print xi6 elseif bi, j = 7 then PRINT-LCS(b, X, i - 1, j)8 else PRINT-LCS(b, X, i, j - 1)该过程的运行时间为O(m+n)。-ok,最后给出此面试第56题的代码,请君自看:参考代码如下:#include string.h/ directions of LCS generationenum decrea

11、seDir kInit = 0, kLeft, kUp, kLeftUp;/ Get the length of two strings LCSs, and print one of the LCSs/ Input: pStr1 - the first string/ pStr2 - the second string/ Output: the length of two strings LCSsint LCS(char* pStr1, char* pStr2) if(!pStr1 | !pStr2) return 0; size_t length1 = strlen(pStr1); size

12、_t length2 = strlen(pStr2); if(!length1 | !length2) return 0; size_t i, j; / initiate the length matrix int *LCS_length; LCS_length = (int*)(new intlength1); for(i = 0; i length1; + i) LCS_lengthi = (int*)new intlength2; for(i = 0; i length1; + i) for(j = 0; j length2; + j) LCS_lengthij = 0; / initi

13、ate the direction matrix int *LCS_direction; LCS_direction = (int*)(new intlength1); for( i = 0; i length1; + i) LCS_directioni = (int*)new intlength2; for(i = 0; i length1; + i) for(j = 0; j length2; + j) LCS_directionij = kInit; for(i = 0; i length1; + i) for(j = 0; j LCS_lengthij - 1) LCS_lengthi

14、j = LCS_lengthi - 1j; LCS_directionij = kUp; / it comes from the left entry in the direction matrix else LCS_lengthij = LCS_lengthij - 1; LCS_directionij = kLeft; LCS_Print(LCS_direction, pStr1, pStr2, length1 - 1, length2 - 1); /调用下面的LCS_Pring 打印出所求子串。 return LCS_lengthlength1 - 1length2 - 1; /返回长度

15、。/ Print a LCS for two strings/ Input: LCS_direction - a 2d matrix which records the direction of/ LCS generation/ pStr1 - the first string/ pStr2 - the second string/ row - the row index in the matrix LCS_direction/ col - the column index in the matrix LCS_directionvoid LCS_Print(int *LCS_direction

16、, char* pStr1, char* pStr2, size_t row, size_t col) if(pStr1 = NULL | pStr2 = NULL) return; size_t length1 = strlen(pStr1); size_t length2 = strlen(pStr2); if(length1 = 0 | length2 = 0 | !(row length1 & col 0 & col 0) LCS_Print(LCS_direction, pStr1, pStr2, row - 1, col - 1); / print the char printf(

17、%c, pStr1row); else if(LCS_directionrowcol = kLeft) / move to the left entry in the direction matrix if(col 0) LCS_Print(LCS_direction, pStr1, pStr2, row, col - 1); else if(LCS_directionrowcol = kUp) / move to the up entry in the direction matrix if(row 0) LCS_Print(LCS_direction, pStr1, pStr2, row

18、- 1, col); 扩展:如果题目改成求两个字符串的最长公共子字符串,应该怎么求?子字符串的定义和子串的定义类似,但要求是连续分布在其他字符串中。比如输入两个字符串BDCABA和ABCBDAB的最长公共字符串有BD和AB,它们的长度都是2。附注:算法导论上指出,一、最长公共子序列问题的一个一般的算法、时间复杂度为O(mn)。然后,Masek和Paterson给出了一个O(mn/lgn)时间内执行的算法,其中n=m,而且此序列是从一个有限集合中而来。在输入序列中没有出现超过一次的特殊情况中,Szymansk说明这个问题可在O((n+m)lg(n+m))内解决。二、一篇由Gilbert和Moore撰写的关于可变长度二元编码的早期论文中有这样的应用:在所有的概率pi都是0的情况下构造最优二叉查找树,这篇论文给出一个O(n3)时间的算法。Hu和Tucker设计了一个算法,它在所有的概率pi都是0的情况下,使用O(n)的时间和O(n)的空间,最后,Knuth把时间降到了O(nlgn)。关于此动态规划算法更多可参考 算法导论一书第15章 动态规划问题,

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1