您的位置:首页 > 其它

51Nod-1006-最长公共子序列Lcs

2016-04-15 18:08 375 查看
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的)。

比如两个串为:

abcicba

abdkscab

ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列。

Input

第1行:字符串A

第2行:字符串B

(A,B的长度 <= 1000)

Output

输出最长的子序列,如果有多个,随意输出1个。

Input示例

abcicba

abdkscab

Output示例

abca

分析:此题的切入点就是动归,通过动归来确定哪些字符是最长公共子序列中的字符,mat[i][j] 表示第一个序列的前i个字符和第二个序列的前j个字符的公共子序列,动态转移方程为:

mat[i][j] = max(mat[i-1][j], mat[i][j-1], mat[i-1][j-1] + (A[i]==B[j] ? 1 : 0));//表示在这三种状态中取到最大值,第一种状态表示不录入第一个序列的第i个字符时的最长公共子序列,第二种状态表示不录入第二个序列的第j个字符时的最长公共子序列,第三种状态表示第一个序列的前i-1个字符与第二个序列前j-1个字符的公共子序列加上最后一个字符的录入状态,如果最后的一个字符相等则录入状态为1,否则为0

然后根据动归的状态,来判断我们要求得的序列中的字符有哪些。

代码如下(C):

#include <stdio.h>
#define  MAXN  1002
char A[MAXN] = {0};
char B[MAXN] = {0};
char R[MAXN] = {0};
short mat[MAXN][MAXN] = {0};

//返回三个数的最大值
short max(short a, short b, short c)
{
if(a > b)
{
b = a;
}
return  b > c ? b : c;
}

int main()
{
int  i, j = 0, k;
scanf("%s %s", A + 1, B + 1);
for(i = 1; A[i]; i++)
{
for(j = 1; B[j]; j++)
{
mat[i][j] = max(mat[i-1][j], mat[i][j-1], mat[i-1][j-1] + (A[i]==B[j] ? 1 : 0));
}
}
i--;
j--;
k = MAXN - 1;
while(i > 0 && j > 0)
{
if(A[i] == B[j])
{
R[k--] = A[i];
i--;
j--;
}
else if(mat[i-1][j] > mat[i][j-1])
{
i--;
}
else
{
j--;
}
}
printf( "%s\n", R + k + 1);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: