f(i,j)= {f(i-1,j-1)+1 (a[i]==b[j])
max(f(i-1,j),f(i,j-1)) (a[i]!=b[j])
由于f(i,j)只和f(i-1,j-1), f(i-1,j)和f(i,j-1)有关, 而在计算f(i,j)时, 只要选择一个合适的顺序, 就可以保证这三项都已经计算出来了, 这样就可以计算出f(i,j). 这样一直推到f(len(a),len(b))就得到所要求的解了.
#include<stdio.h>
#include<string.h>
int t[1000][1000];
int max(int x,int y)
{
if(x>y)
return x;
else
return y;
}
int main()
{
char a[1000],b[1000];
int n,m,i,j;
// freopen("1159.txt","r",stdin);
memset(a,0,1000*sizeof(char));
memset(b,0,1000*sizeof(char));
while(scanf("%s%s%*c",a,b)!=EOF)
{
memset(t,0,sizeof(t));
n=strlen(a);
m=strlen(b);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(a[i-1]==b[j-1])
t[i][j]=t[i-1][j-1]+1;
else
t[i][j]=max(t[i-1][j],t[i][j-1]);
}
}
printf("%d\n",t[n][m]);
}
}
修改后同时可以输出最长公共子序列
#include<stdio.h>
#include<string.h>
int t[1000][1000],c[1000][1000];
int main()
{
char a[1000],b[1000],e[1000];
int n,m,i,j,k,len;
freopen("1159.txt","r",stdin);
memset(a,0,1000*sizeof(char));
memset(b,0,1000*sizeof(char));
while(scanf("%s%s%*c",a,b)!=EOF)
{
memset(e,0,sizeof(e));
memset(t,0,sizeof(t));
n=strlen(a);
m=strlen(b);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(a[i-1]==b[j-1])
{
t[i][j]=t[i-1][j-1]+1;
c[i][j]=1;//对角线方向
}
else if(t[i-1][j]>t[i][j-1])
{
t[i][j]=t[i-1][j];
c[i][j]=2;//上面来的
}
else
{
t[i][j]=t[i][j-1];
c[i][j]=3;//左边来的
}
}
}
printf("%d\n",t[n][m]);
i=n;
j=m;
len=t[n][m];
k=len;
while(k)
{
if(c[i][j]==1)
{
i--;
j--;
e[k-1]=a[i];
k--;
}
else if(c[i][j]==2)
{
i--;
}
else if(c[i][j]==3)
{
j--;
}
}
for(i=0;i<len;i++)
{
printf("%c ",e[i]);
if(i<len-1)
putchar(' ');
else if(i==len-1)
printf("\n");
}
}
return 0;
}