废话不说,直接入主题。这次讨论的是动态规划问题。动态规划可通过找重叠的子问题,以及解决子问题的方法进行问题化简最终达到解决的目的。以例子进行说明:寻找最长公共子序列;寻找非降序最长子序列。
1.寻找最长公共子序列
题目:两个序列A、B,长度不定,寻找其最长公共子序列,要求顺序一致。
印象:其中一个做标准A,B则用于与标准进行比对。但是B的元素如果在A中找到了,要如何操作,没有找到又要怎样,顺序问题怎么解决呢。
分析:a.解题的思路就是将问题由大化小,当然还要知道小问题如何解决。
b.由大化小:都是两个序列求解最长公共序列,这是每个问题的相同部分。可通过将序列变短以达到由大化小的目的。
c.小问题解决方法:最简单的小问题是:两个只有一个元素的序列求解,相等即是公共解。
d.分别具有两个元素的序列A,B:如果A序列第一个元素a1与B中第一个元素b1相等,则可算为公共序列。在此基础上,将a2与b2进行比对即可;
如果a1!= b1,则公共解可能产生于a1=b2 or a2=b2,即是A序列(a1,a2)与b2求解公共最长序列;公共解也可能产生于b1=a2 or b2=a2,即是B序列与a2求解最长公共序列,至于是那种可能性,当然是两者之间公共序列最长的那个。
题解(未写成程序):
A:a1,a2,a3,a4,……,an
B:b1.b2,b3,b4,……,bm
由分析可知,当a1=b1时,即化成序列A2(a2--an)与B2(b2--bm)求解最长公共序列;当a1!=b1时,即是在A2与B1,A1与B2两种当中选择具有最长公共序列的即是。
计算时,需要先将An与Bm的公共解求出(标记为c(n,m),c为公共序列中含有元素的个数),再将序列An-1与Bm公共解求出(c(n-1,m)),序列An与Bm-1公共解求出(c(n,m-1));An-1与Bn-1的公共解(c(n-1,m-1)即可通过c(n,m),c(n-1,m),c(n,m-1)求出。规则是:当an-1=bm-1时,将从c(n,m)+1即是当前最长公共序列所含元素个数,an-1即是公共序列的元素之一。当an-1!=bm-1时,即是查看c(n-1,m)和c(n,m-1)中哪个大,就选哪个作为c(n-1,m-1)的值,它所含有的公共元素也是由c(n-1,m)或是 c(n,m-1)决定(看选的是哪个了)。
2.寻找最长非降序子序列
题目:多个元素组成的一个无序的序列,求其最长、非降序、子序列。
印象:非降序,子序列都好说,如何达到最长,是个问题。
一个元素的序列,它的最长非降序子序列(后简称解)就是这个元素;两个元素组成的序列,就需要查看第二个元素是否大于等于第一个元素,决定结果;三个元素组成的序列,需要查看是否大于第一个元素,是否大于第二个元素,还得看看两个元素时的结果来综合考虑它的解是什么。
这样做很麻烦,也很乱。这样做之所以麻烦,是因为在每增加一个元素的时候,我都想得出当前那个元素在最后的解之中,哪个元素不在。其实可以换一种想法,每增加一个元素,就认为它在解中,也就是确定了在当前情况下结尾的那个数(新增加的那个元素)。那么为了满足非降序条件,需要最后一个元素大于等于它前面的元素,也就是他前面的都小于等于最后一个元素。
分析:依然是由大化小。假定以当前序列的每一个元素为最后一个元素的解都已经存在,那么每增加一个元素我们在它前面找到比其小于等于的元素,找到比较哪一个对应的解比较长,就把最好的放在新增加的这个元素的前面,即是求出了以新增元素为结尾的解。
题解(未写成程序):
假定序列A:1,5,6,1,2,3……
以哪个元素为结尾 比其小的元素(对应的解) 对应的解
1 null 1
5 1(1) 1,5
6 1(1),5(1,5) 1,5,6
1 1(1) 1,1
2 1(1),1(1,1) 1,1,2
3 1(1),1(1,1),2(1,1,2) 1,1,2,3
…… ……………… ………
这样推算下去,直到真正的最后一个元素,结果即可得出。