一.问题分析
最长公共子序列的求解:问题描述:最长公共子序列(LCS)是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题。一个数列,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则称为已知序列的最长公共子序列。
要求:给定两个序列,设计算法求出这两个序列的最长公共子序列是什么。
二.问题的解决方案/算法选择/设计思路。描述及绘制出解决方案/算法的功能结构框图;
解决方案:
最长公共子序列问题是属于动态规划的一部分,我们首先来举一个例子用来解决最长子序列问题:求长为m的序列和长为n的序列的最长公共子序列(可以不连续),如ABCBDAB和BDCABA,BCAB和BCBA都是它们的最长公共子序列。其中用到了数据结构和c语言等知识。
设计思路:
#include
#include
char a[300],b[300];
char num[301][301]; ///记录中间结果的数组
char flag[301][301]; ///标记数组,用于标识下标的走向,构造出公共子序列
void LCS(); ///动态规划求解
void getLCS(); ///采用倒推方式求最长公共子序列
int main()
{
int i;
strncpy(a,"ABCBDAB");
strncpy(b,"BDCABA");
memmove(num,0,sizeof(num));
memmove(flag,0,sizeof(flag));
LCS();
printf("%d\n",num[wcslen(a)][wcslen(b)]);
getLCS();
return 0;
}
void LCS()
{
int i,j;
for(i=1;i<=stolen(a);i++)
{
for(j=1;j<=stolen(b);j++)
{
if(a[i-1]==b[j-1]) ///注意这里的下标是i-1与j-1
{
num[i][j]=num[i-1][j-1]+1;
flag[i][j]=1; ///斜向下标记
}
else if(num[i][j-1]>num[i-1][j])
{
num[i][j]=num[i][j-1];
flag[i][j]=2; ///向右标记
}
else
{
num[i][j]=num[i-1][j];
flag[i][j]=3; ///向下标记
}
}
}
}
void getLCS()
{
char res[300];
int i=wclsen(a);
int j=wclsen(b);
int k=0; ///用于保存结果的数组标志位
while(i>0 && j>0)
{
if(flag[i][j]==1) ///如果是斜向下标记
{
res[k]=a[i-1];
k++;
i--;
j--;
}
else if(flag[i][j]==2) ///如果是斜向右标记
j--;
else if(flag[i][j]==3) ///如果是斜向下标记
i--;
}
for(i=k-1;i>=0;i--)
printf("%c",res[i]);
}
设计思路:
首先我们要,明白这个问题得本质,首先来说此问题在于时相同的最长子序列问题,其实通俗的来讲我们只用看他们到底有多少个相同的元素罢了。
我们是用动态规划得方式解决此问题:
动态规划解决问题一般有两种特征(最优子结构和重叠子问题)
①最优子结构:
设X =(x1,x2,..... xn)和Y = {y1,y2,..... ym}是两个序列,将X和Y的最长公共子序列记为LCS(X ,Y)
找出LCS(X,Y)就是一个最优化问题。因为,我们需要找到X和ý中最长的那个公共子序列。而要找X和Y的LCS,首先考虑X的最后一个元素和Y的最后一个元素。
1)如果Xn = Ym,即X的最后一个元素与Y的最后一个元素相同,这说明该元素一定位于公共子序列中。因此,现在只需要找:LCS(Xn-1,Ym-1)
LCS(XN-1,YM-1)就是原问题的一个子问题。为什么叫子问题?因为它的规模比原问题小。
为什么是最优的子问题?因为我们要找的是XN-1和YM-1的最长公共子序列啊......最长的!换句话说,就是最优的那个。(这里的最优就是最长的意思)
2)如果Xn!= Ym,这里会稍有些复杂,因为它产生了两个子问题:LCS(Xn-1,Ym)和LCS(Xn,Ym-1)
因为序列X和序列Y的最后一个元素不相等,说明那一个求最后元素不可能的英文最长公共子序列中的元素。
LCS(Xn-1,Ym)表示:最长公共序列可以在(x1,x2,...... x(n-1))和(y1,y2,... yn)中找。
LCS(Xn,Ym-1)表示:最长公共序列可以在(x1,x2,... xn)和(y1,y2,... y(n-1))中找。
求解上面两个子问题,得到的公共子序列谁最长,那谁就是LCS(X,Y)用数学表示就是:
LCS = MAX {LCS(XN-1,YM),LCS(XN,YM-1)}
由于条件1)和2)考虑到了所有可能的情况。因此,我们成功地把原问题转化成了三个规模更小的子问题。