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; }