DP入门——最长公共子序列(LSC)
背景提示:一个给定的序列的子序列是在该序列中删去若干元素后得到的序列(并非连续)。
问题:给定两个序列x与y,当另一个序列z既是x的子序列又是y的子序列的时候,就称z为x与y的公共子序列,其中最长的为最长公共子序列。
——————————————————————————————
思路:
在我们寻求xi与yj的LCS之前,我们应该明白它是由x(i-1)和y(j-1)的LCS递推得到的,那么我们就来看看递推的过程。首先,从x(j-1)与y(j-1)递推到下一项时,我们应当判断序列x与y里面的哪一个元素应该加入到公共子序列中。
这里分两种情况讨论xi=yj与xi!=yj(不等于)的情况。前者很容易解决,直接加上两者一样的那一位元素。而第二种情况则需要我们的讨论,是加上xi的子序列长度会更长还是加上yi的子序列长度会更长呢?
下面我们举一个例子:(来自《算法竞赛入门到进阶》p128)
序列 X=(a,b,c,f,b,c) Y=(a,b,f,c,a,b) 用 L[i][j] 来表示Xi与Yi的最长公共子序列的长度。
首先我们作图
通过这个表格,我们可以看出其实我们是在比较不同的选择递推出的下一步结果,比如在L[1][1]的时候,X1=Y1,所以L[1][1]=L[0][0]+1=1。在L[1][2]的时候,X1不等于Y2,则在L[1][1]与L[0][2]之间选择最大的一个接上去。
继续以上过程,最后得到答案。
接下来是代码实现
#include<bits/stdc++.h>
using namespace std;
int dp[1005][1005];
string str1,str2; //通过字符串实现序列的输入
int LCS()
{
memset(dp,0,sizeof(dp)); //初始化
for(int i=1;i<=str1.length();i++)
for(int j=1;j<=str2.length();j++)
{
if(str1[i-1]==str2[j-1]) //相同
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
return dp[str1.length()][str2.length()];
}
int main()
{
while(cin>>str1>>str2)
{
cout<<LCS()<<endl;
}
return 0;
}
就这么多啦!