问题描述:
最长公共子序列问题(Longest Common Subsequence problem):给定两个序列X = <x1,x2,…,xm>和Y = <y1,y2,…,yn>,求X和Y长度最长的公共子序列。
状态表示:
F[i,j]表示前缀子串A[1 ~ i]与B[1 ~ j]的“最长公共子序列”的长度。
阶段划分:已处理的前缀长度(两个字符串中的位置,即一个二维坐标)
转移方程:
A[i]=B[j],表示F[i-1][j-1]+1,表示A[i]和B[j]匹配。
当A[i]和B[j]不匹配,就看A[i]和B[j-1]配对,A[i-1]和B[j]配对,那个大
边界:F[i,0]=F[0,i]=0。
目标:F[N,M]。
样例:
ABCBDAB
BDCABA
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1000;
char a[N],b[N];
int F[N][N];
int main()
{
int lena,lenb,i,j;
while(scanf("%s%s",a,b)!=EOF) //EOF ctrl+z,回车键
{
memset(F,0,sizeof(F));
lena=strlen(a);
lenb=strlen(b);
for(i=1;i<=lena;i++)
{
for(j=1;j<=lenb;j++)
{
if(a[i-1]==b[j-1])
{
F[i][j]=F[i-1][j-1]+1;
}
else
{
F[i][j]=max(F[i-1][j],F[i][j-1]);
}
}
}
printf("%d\n",F[lena][lenb]);
}
return 0;
}
最长公共子序列用递归法打印路径
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;
char x[N],y[N];
int F[N][N];
int b[N][N];
void Print(int i,int j)
{
if(i==0||j==0)///递归终止条件
{
return ;
}
if(b[i][j]==1)
{
Print(i-1,j-1);
printf("%c",x[i-1]);
}
else if(b[i][j]==2)
{
Print(i-1,j);
}
else if(b[i][j]==3)
{
Print(i,j-1);
}
}
int main()
{
int lena,lenb,i,j;
while(scanf("%s%s",x,y)!=EOF)
{
memset(F,0,sizeof(F));
memset(b,0,sizeof(b));
lena=strlen(x);
lenb=strlen(y);
for(i=1;i<=lena;i++)
{
for(j=1;j<=lenb;j++)
{
if(x[i-1]==y[j-1])
{
F[i][j]=F[i-1][j-1]+1;
b[i][j]=1;///来自于左上方
}
else
{
if(F[i-1][j]>F[i][j-1])
{
F[i][j]=F[i-1][j];
b[i][j]=2;///来自于左方
}
else
{
F[i][j]=F[i][j-1];
b[i][j]=3;///来自于上方
}
}
}
}
//打表
cout<<" ";
for(int i = 1; i <= lenb; i++)
{
cout<<" "<<y[i-1];
}
cout<<"\n";
for(int i = 0 ; i <= lena; i++){
if(i != 0)
cout<<x[i-1]<<" ";
else
cout<<" ";
for(int j = 0; j <= lenb; j++){
cout<<F[i][j]<<" ";
}
cout<<"\n";
}
printf("%d\n",F[lena][lenb]);
Print(lena,lenb);
}
return 0;
}
/*
ABCBDAB
BDCABA
*/
结果如下图: