最长公共子序列问题(LCS,Longerst Common Subsequence)。
s1s2……si+1和t1t2……tj+1的公共子序列可能是:
①当si+1=tj+1时,在s1s2……si+1和t1t2……tj+1的公共子序列末尾追加一个。
②s1s2……si+1和t1t2……tj的公共子序列
③s1s2……si和t1t2……tj+1的公共子序列
所以易得到递推关系dp[i+1][j+1]= max{ dp[i][j]+1 , dp[i][j+1] , dp[i+1][j]) } (当si+1=tj+1时)
max{ dp[i][j+1] , dp[i+1][j]) } (其他)
最后得到的dp[n][m]就是LCS的长度。
同时稍微思考一下,就可以发现当si+1=tj+1时,dp[i+1][j+1]只要等于dp[i][j]+1就可以了。
tips:
怎么 思考呢 ,首先因为si+1=tj+1,显然si和tj+1,si+1和 tj均不相等。那么 dp[i][j+1] 和 dp[i+1][j] 其实也就等于dp[i][j]。
①要注意的是s1第i个字母在数组中的位置是s1[i-1]而不是s[i],s2同理。所以下面这个判断的是s1[i-1]==s2[j-1] 它想表达的就是s1的第i个字母与s2的第j个字母是否相等,所以与上面的递推式是一致的
1 if( s1[i-1] == s2[j-1] ) 2 dp[i][j] = dp[i-1][j-1]+1; 3 else 4 dp[i][j] = max( dp[i-1][j] , dp[i][j-1] );
其实啊 我想了想 觉得这个数组从0开始用和从1开始用 还是很有讲究的。
AC代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 int dp[5000][5000]; 7 char s1[5000],s2[5000]; 8 int main() 9 { 10 11 while(~scanf("%s%s",&s1,&s2)) 12 { 13 int len1=strlen(s1); 14 int len2=strlen(s2); 15 for(int i=0 ; i <= len1 ; i++) 16 dp[i][0]=0; 17 for(int j=0 ; j <= len2 ; j++) 18 dp[0][j]=0; 19 20 for(int i=1 ; i <= len1 ; i++) 21 for(int j=1 ; j <= len2 ; j++) 22 { 23 if( s1[i-1] == s2[j-1] ) 24 dp[i][j] = dp[i-1][j-1]+1; 25 else 26 dp[i][j] = max( dp[i-1][j] , dp[i][j-1] ); 27 } 28 printf("%d\n", dp[len1][len2] ); 29 } 30 return 0; 31 }
时间: 2024-10-24 18:12:09