ACM动态规划算法_C语言.
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Baidu Nhomakorabea
显然上述算法的实现与前面的例子相同。如果希望求出其 最长公共子序列,可设置一个数组b[i][j],用于记录是哪一个 子序列求得的解。 当b[i][j]=1时,表示Zk是在原来Zk-1的基础上加上Xi或者Yj 得到,因为此时Xi=Yj。
当b[i][j]=2时,表示Xi和Yj的最长公共子序列与Xi-1和Yj 的 最长公共子序列相同。 当b[i][j]=3时,表示Xi和Yj的最长公共子序列与Xi和Yj 的 最长公共子序列相同。
可通过求得的b[i][j]然后再计算出其最后的子序列。当然 也可在求解过程中计算其最后的最序列。其程序见 MaxLength.cpp.
该算法还可作一定程度的改进以提高其运行速度。
例3:已知某整数序列A=(a1,a2,…,an),求该序列的最大 子段和。 分析:显然要求其最大子段和可通过一个3重循环求得。 首先把序列分解成两个部分,对于前一部分,我们已经计算 出其所有可能的组合结果,后一部分则分别计算其所有组合 中的最大值,并于前面求得的最大值进行比较,如果比前面 求得的最大值还大则取代前面的最大值。这样可求得其最大 子段和。 上述算法执行时间太长。可采用分治法求解,以降低时 间复杂度。 分治法的思想是将序列分解成两个相同的部分,显然可 得到如下几种情形: (1)整个序列的最大子段和与前一部分的最大子段和同。 (2)整个序列的最大子段和与后一部分的最大子段和同。
分析: 设m[i][j]表示计算出Ai Ai+1…Aj所需要的最少次乘 法运算。而假设要得出这样的最优解需要从第k个位置断开, 这样就将其分解成两个部分,前一部分的最优计算次数为 m[i][k], 后一部分的最优次序为m[k+1][j],显然有下面的表
达式存在: m[i][j]=0; i=j 因为在i=j时表示只有一个矩阵,没有进行乘法运算,其 乘法运算的次数为0。 m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj 其中i<=k<j 由于k的位置是未知的,因此需要求其最小值: m[i][j]=min(m[i][k]+m[k+1][j]+pi-1pkpj) 其中i<=k<j 只要计算出所有可能的组合中的最小值就可以计算出 m[i][j]的值。 比如计算A0[10][100]*A1[100][50]*A2[50][2]的最小乘法 次数,可采用如下的计算步骤获得: m[0][2]=min(m[0][0]+m[1,2]+10*100*2,m[0][1]+m[2][2] +10*50*2)=min(100*50*2+10*100*2, 10*100*50+10*50*2) =12,000
对于算A0[10][100]*A1[100][50]*A2[50][2]*A4[2][10]的最 小乘法次数,可采用如下的计算步骤获得: m[0][4]=min(m[0][0]+m[1][3]+10*100*10,m[0][1]+m[2][3] +10*50*10, m[0][2]+m[3][3]+10*2*10)=12200; k=2; 其中:m[0][0]=m[3][3]=m[1][1]=m[2][2]=0; m[2][3]=50*2*10=1000; m[1][2]=2*100*50=10000; m[0][1]=10*100*50=50000; m[1][3]=min(m[1][1]+m[2][3]+100*50*10, m[1][2]+ m[3][3]+100*2*10)=12000; 此时k=2; m[0][2]=min(m[0][0]+m[1][2]+10*100*2, m[0][1]+ m[2][2]+10*50*2)=12000; 此时k=0; 从上面的计算过程可以看出,如果先计算出m[1][2]就可 计算出m[0][2], 先计算出m[2][3]就可计算出m[1][3], 因此可
从上面的求解过程来看,动态规划问题取决于两个重要 的性质: 1、最优子结构性质:问题的最优解包含了其子问题的最 优解。 2、子问题重叠性质:后续问题的求解可通过前面的子问 题的求解结果计算出来。 因此可通过动态规划基本上可通过递归算法实现。 例2:设序列X={x1,x2,x3…,xm}, Y={y1,y2,y3,…,yn}, 求这 两个序列的最长公共子序列Z。 设Z={z1,z2,z3,…zk}, 则必有下面的结论存在: (1)如果xm=yn,说明xm或yn一定是最长公共子序列中的最 后一个元素,即zk=xm=yn。同样可以得出{z1,z2,z3,…, zk-1}是 序列Xm-1和Yn-1的最长公共子序列。
(2)如果xm≠yn且zk≠xm,说明xm不是Z中的一个元素,Z中 的元素与X中的最后一个元素无关,因此Z是Xm-1与Yn的最长公 共子序列。 (3)如果xm≠yn且zk≠yn,说明yn不是Z中的一个元素,Z中 的元素与Y中的最后一个元素无关,因此Z是Xm与Yn-1的最长公 共子序列。 基于上述认识,我们可以建立一个数组C[i][j]用于记录 Xi和Yj的最长公共子序列的长度,显然有如下的表达式成立。 (1)当i=0或者j=0时,C[i][j]=0; (2)当i,j>0且xi=yj时,C[i][j]=C[i-1][j-1]+1; (3)当i,j>0且xi≠yj时,C[i][j]=max(C[i][j-1],C[i-1] [j]} 因此只要计算出上面的递推式就可以计算出其长度。
动态规划算法
动态规划算法的特点:
动态归化算法是将问题分解成若干个子问题,通过求解 这些子问题的最优解来求整个问题的最优解。与分治法不同 的是,这些子问题往往并不相互独立,不能将子问题的解作 为最后问题的解。动态规划往往用于求解问题的最优解。 例1:给定n个矩阵的连乘表达式,求其最少需要多少次 乘法运算才能计算出乘法运算的结果。
采用自底向上的计算方法进行计算。如上例中,可采用如下 的计算顺序: m[0][0]->m[1][1]->m[2][2]->m[3][3] m[0][1]->m[1][2]->m[2][3] m[0][2]->m[1][3] m[0][3] 从上面的计算顺序可以看出类似于一个上三角矩阵,先 计算斜线上的元素,并依次向上递推。 如果希望知道采用何种方式才能实现乘法次数最少,可用 一个数组s[i][j]来记录m[i][j]最优解时的k值。每一个m[i][j]对应 一个s[i][j],这样就可知道如何分解上述矩阵表达式以得到最 小的乘法次数了。上例中k值依次为0->2 在上例中,最后的分解结果为(A0[10][100]*(A1[100][50]* A2[50][2]))*A4[2][10]。
显然上述算法的实现与前面的例子相同。如果希望求出其 最长公共子序列,可设置一个数组b[i][j],用于记录是哪一个 子序列求得的解。 当b[i][j]=1时,表示Zk是在原来Zk-1的基础上加上Xi或者Yj 得到,因为此时Xi=Yj。
当b[i][j]=2时,表示Xi和Yj的最长公共子序列与Xi-1和Yj 的 最长公共子序列相同。 当b[i][j]=3时,表示Xi和Yj的最长公共子序列与Xi和Yj 的 最长公共子序列相同。
可通过求得的b[i][j]然后再计算出其最后的子序列。当然 也可在求解过程中计算其最后的最序列。其程序见 MaxLength.cpp.
该算法还可作一定程度的改进以提高其运行速度。
例3:已知某整数序列A=(a1,a2,…,an),求该序列的最大 子段和。 分析:显然要求其最大子段和可通过一个3重循环求得。 首先把序列分解成两个部分,对于前一部分,我们已经计算 出其所有可能的组合结果,后一部分则分别计算其所有组合 中的最大值,并于前面求得的最大值进行比较,如果比前面 求得的最大值还大则取代前面的最大值。这样可求得其最大 子段和。 上述算法执行时间太长。可采用分治法求解,以降低时 间复杂度。 分治法的思想是将序列分解成两个相同的部分,显然可 得到如下几种情形: (1)整个序列的最大子段和与前一部分的最大子段和同。 (2)整个序列的最大子段和与后一部分的最大子段和同。
分析: 设m[i][j]表示计算出Ai Ai+1…Aj所需要的最少次乘 法运算。而假设要得出这样的最优解需要从第k个位置断开, 这样就将其分解成两个部分,前一部分的最优计算次数为 m[i][k], 后一部分的最优次序为m[k+1][j],显然有下面的表
达式存在: m[i][j]=0; i=j 因为在i=j时表示只有一个矩阵,没有进行乘法运算,其 乘法运算的次数为0。 m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj 其中i<=k<j 由于k的位置是未知的,因此需要求其最小值: m[i][j]=min(m[i][k]+m[k+1][j]+pi-1pkpj) 其中i<=k<j 只要计算出所有可能的组合中的最小值就可以计算出 m[i][j]的值。 比如计算A0[10][100]*A1[100][50]*A2[50][2]的最小乘法 次数,可采用如下的计算步骤获得: m[0][2]=min(m[0][0]+m[1,2]+10*100*2,m[0][1]+m[2][2] +10*50*2)=min(100*50*2+10*100*2, 10*100*50+10*50*2) =12,000
对于算A0[10][100]*A1[100][50]*A2[50][2]*A4[2][10]的最 小乘法次数,可采用如下的计算步骤获得: m[0][4]=min(m[0][0]+m[1][3]+10*100*10,m[0][1]+m[2][3] +10*50*10, m[0][2]+m[3][3]+10*2*10)=12200; k=2; 其中:m[0][0]=m[3][3]=m[1][1]=m[2][2]=0; m[2][3]=50*2*10=1000; m[1][2]=2*100*50=10000; m[0][1]=10*100*50=50000; m[1][3]=min(m[1][1]+m[2][3]+100*50*10, m[1][2]+ m[3][3]+100*2*10)=12000; 此时k=2; m[0][2]=min(m[0][0]+m[1][2]+10*100*2, m[0][1]+ m[2][2]+10*50*2)=12000; 此时k=0; 从上面的计算过程可以看出,如果先计算出m[1][2]就可 计算出m[0][2], 先计算出m[2][3]就可计算出m[1][3], 因此可
从上面的求解过程来看,动态规划问题取决于两个重要 的性质: 1、最优子结构性质:问题的最优解包含了其子问题的最 优解。 2、子问题重叠性质:后续问题的求解可通过前面的子问 题的求解结果计算出来。 因此可通过动态规划基本上可通过递归算法实现。 例2:设序列X={x1,x2,x3…,xm}, Y={y1,y2,y3,…,yn}, 求这 两个序列的最长公共子序列Z。 设Z={z1,z2,z3,…zk}, 则必有下面的结论存在: (1)如果xm=yn,说明xm或yn一定是最长公共子序列中的最 后一个元素,即zk=xm=yn。同样可以得出{z1,z2,z3,…, zk-1}是 序列Xm-1和Yn-1的最长公共子序列。
(2)如果xm≠yn且zk≠xm,说明xm不是Z中的一个元素,Z中 的元素与X中的最后一个元素无关,因此Z是Xm-1与Yn的最长公 共子序列。 (3)如果xm≠yn且zk≠yn,说明yn不是Z中的一个元素,Z中 的元素与Y中的最后一个元素无关,因此Z是Xm与Yn-1的最长公 共子序列。 基于上述认识,我们可以建立一个数组C[i][j]用于记录 Xi和Yj的最长公共子序列的长度,显然有如下的表达式成立。 (1)当i=0或者j=0时,C[i][j]=0; (2)当i,j>0且xi=yj时,C[i][j]=C[i-1][j-1]+1; (3)当i,j>0且xi≠yj时,C[i][j]=max(C[i][j-1],C[i-1] [j]} 因此只要计算出上面的递推式就可以计算出其长度。
动态规划算法
动态规划算法的特点:
动态归化算法是将问题分解成若干个子问题,通过求解 这些子问题的最优解来求整个问题的最优解。与分治法不同 的是,这些子问题往往并不相互独立,不能将子问题的解作 为最后问题的解。动态规划往往用于求解问题的最优解。 例1:给定n个矩阵的连乘表达式,求其最少需要多少次 乘法运算才能计算出乘法运算的结果。
采用自底向上的计算方法进行计算。如上例中,可采用如下 的计算顺序: m[0][0]->m[1][1]->m[2][2]->m[3][3] m[0][1]->m[1][2]->m[2][3] m[0][2]->m[1][3] m[0][3] 从上面的计算顺序可以看出类似于一个上三角矩阵,先 计算斜线上的元素,并依次向上递推。 如果希望知道采用何种方式才能实现乘法次数最少,可用 一个数组s[i][j]来记录m[i][j]最优解时的k值。每一个m[i][j]对应 一个s[i][j],这样就可知道如何分解上述矩阵表达式以得到最 小的乘法次数了。上例中k值依次为0->2 在上例中,最后的分解结果为(A0[10][100]*(A1[100][50]* A2[50][2]))*A4[2][10]。