状态转移方程如下:
刚开始完全不理解当xi!=yj时,为什么Cij要等于
以s1作为标准,当前已经s1下标为i(即i不变,j在变化),匹配时s2的j是依次递增的,那么当s1i!=s2j时,那么此时Cij的值就是C[i,j-1]的值
以s2作为标准,当前已经s2下标为j(即j不变,i在变化),匹配时s1的i是依次递增的,那么当s1i!=s2j时,那么此时Cij的值就是C[i-1,j]的值
正因为Cij可视为以上两种不同标准的匹配,所以Cij就取其中最大那个值作为Cij
推荐博文:1点击打开链接 2点击打开链接 感谢两位dalao讲解!谢谢!
#include<stdio.h> #include<string> #include<string.h> #include<iostream> #include<algorithm> using namespace std; char s1[100],s2[100]; int maxlen[100][100];//用来保存每个状态的最长公共子序列长度 int flag[100][100];//用来记录路径,方便输出最长公共子序列 void LCS() { int i,j,k,len1,len2; len1=strlen(s1); len2=strlen(s2); for(i=0; i<=len1; i++)//当i=0或者j=0时,maxlen赋为0 maxlen[i][0]=0; for(i=0; i<=len2; i++) maxlen[0][i]=0; memset(flag,0,sizeof(flag)); for(i=1; i<=len1; i++) { for(j=1; j<=len2; j++) { if(s1[i-1]==s2[j-1])//注意数组下标,amxlen矩阵起始位置为(1,1),而s1,s2数组起始位置为0 { maxlen[i][j]=maxlen[i-1][j-1]+1; flag[i][j]=1;//说明这个位置上s1[i]==s2[j],也可以说是这个值从斜上方而来 } else { if(maxlen[i-1][j]>=maxlen[i][j-1]) { maxlen[i][j]=maxlen[i-1][j]; flag[i][j]=2;//这个值从“上”方而来 } } else { maxlen[i][j]=maxlen[i][j-1]; flag[i][j]=3;//这个值从“左边”而来 } } } } /*for(i=1; i<=len1; i++) { for(j=1; j<=len2; j++) { printf("%d ",flag[i][j]); } printf(" "); } 用来查看flag矩阵 */ } void getLCS() { int i,j,k,len1,len2; i=strlen(s1); j=strlen(s2); char ans[100]; k=0; while(i>0&&j>0) { if(flag[i][j]==1) { ans[k++]=s1[i-1];//注意数组下标,flag矩阵起始位置为(1,1),而s1,s2数组起始位置为0 i--; j--; } else if(flag[i][j]==2)i--; else j--; //实际上就是在寻找flag为'1'的位置,并将那个位置上的s1(或者s2,因为当flag==1时,s1[i]==s2[j])存入结果数组中 } for(j=k-1; j>=0; j--)//倒着输出lcs,因为我们是从尾向头开始找lcs子序列的 printf("%c",ans[j]); printf(" "); } int main() { int len1,len2,i,j; while(scanf("%s%s",s1,s2)!=EOF) { LCS(); printf("%d ",maxlen[strlen(s1)][strlen(s2)]); getLCS(); } return 0; } /* 13456778 357486782 abcbdab bdcaba */
”斜上方“即是当前s1i==s2j,maxlen{i,j}=maxlen[i-1,j-1]+1;
”左方“即是当前最大值来自左边,maxlen{i,j}=maxlen[i,j-1];
上方“即是当前最大值来自上方,maxlen{i,j}=maxlen[i-1,j];