有序子序列定义:若X=<X1 , X2 , X3 , X4 , ... , Xn>则它的子序列为Y=<Xi , Xj , Xk , ... , Xm>,即原序列调出若干项组成的序列且下标要求有序。
LCS(最长公共子序列)定义:给定两个序列X=<X1 , X2 , X3 , X4 , ... , Xn>和Y=<Y1 , Y2 , Y3 , Y4 , ... , Ym>存在一个严格递增的X的下标序列为<i1 , i2 , ... , ik>,对所有的j=1,2,3...k,满足xi=yj,例如X=<1 , 4 , 3 , 2 , 5>,Y=<4 , 3 , 5 , 7>,则X和Y的最长公共子序列为<4 , 3 , 5>(下标不一定要连续).
题目描述:给定两个字符串,,输出他们的最长公共子序列长度。
样例输入:
abcfbc abfcab
programming contest
abcd mnp
样例输出:
4
2
0
源代码:
#include<iostream>
#include<cstring>
#define MAX 1001
using namespace std;
int max( int a , int b ){
return a > b ? a : b;
}
int dp[MAX][MAX];
char str1[MAX] , str2[MAX];
int main( ){
int i , j , len1 , len2;
while( ~scanf("%s %s",str1, str2) )
{
memset( dp , 0 , sizeof( dp ) );
len1 = strlen( str1 );
len2 = strlen( str2 );
for( i=1 ; i<=len1 ; i++ )
for( j=1 ; j<=len2 ; j++ ){
if( str1[i-1] == str2[j-1] )
dp[i][j] = dp[i-1][j-1] + 1;
else
dp[i][j] = max( dp[i-1][j] , dp[i][j-1] );
}
cout<<dp[len1][len2]<<endl;
}
return 0;
}
代码分析:采用动态规划DP的算法来解决LCS问题再好不过了,DP算法要求问题满足最优子结构和重复子问题(纯DFS算法的缺点便显而易见了,子问题已经重复做了若干,花费了开销),不过遵循时空守恒的原则,用了DP你需要开出一个额外的数组,才存储每个状态的最优解,下一个最优解是由子问题的最优解运算而成的。也就是说DP需要一个状态转移方程,描述了问题与子问题间的递推关系。该题中转移方程为{ if(xi==yj)dp[i][j]=dp[i-1][j-1]+1; if( xi!=yj )
dp[i][j]=max(dp[i-1][j] , dp[i][j-1]) },其中dp[i][j]的含义是第一字符串前i个子字符串和第二个字符串的前j个子字符串形成的LCS数。