一个数列 如果分别是两个或多个已知数列的子序列且是所有符合此条件序列中最长的则称为已知序列的最长
公共子序列。
首先 给出最长公共子序列的状态转移方程
- dp[i][j] = 0 如果i=0或j=0
- dp[i][j] = dp[i-1][j-1] + 1 如果X[i-1] ==Y[i-1]
- dp[i][j] = max{ dp[i-1][j], dp[i][j-1] } 如果X[i-1] != Y[i-1]
可以用数组实现 c[i][j]记录序列Xi和Yi的最长公共子序列的长度 当i=0或j=0时 空序列是序列Xi和Yi的最长公共子序列
状态转移方程很好理解 从后往前 当序列X的第i个元素和序列Y的第j个元素相等时 最长公共子序是序列Xi和序列Yj的最长公共子序列 当序列X的第i个元素和序列Y的第j个元素不相等时 最长公共子序列是序列Xi-1和Yj的公共子序列或是序列Xi和序列Yj-1的公共子序列(那个长是那个)
实现代码:
void LCSLlength(int n,int m,char *X,char *Y,int **c,int **b){
int i,j;
memset(c,0,sizeof(c));// c数组清零 需加头文件 <string.h>
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if (X[i-1]==Y[j-1]){// 从0开始输入的字符串 个人习惯
c[i][j]=c[i-1][j-1]+1;
b[i][j]=0;// 输出子序列用
}
else if (c[i-1][j]>=c[i][j-1]){
c[i][j]=c[i-1][j];
b[i][j]=1;// 输出子序列用
}
else{
c[i][j]=c[i][j-1];
b[i][j]=-1;// 输出子序列用
}
}
}
}
再谈怎么输出最长公共子序列 用二维数组b[][]记住每一步的操作是什么 然后递归找到X[i]==Y[j]的情况 输出
实现代码:
void Print(int i,int j,char x[],int **b){
if (i==0||j==0)
return ;
if (b[i][j]==0){
Print(i-1,j-1,x,b);
printf ("%c",x[i-1]);
}
else if(b[i][j]==1){
Print(i-1,j,x,b);
}
else{
Print(i,j-1,x,b);
}
}
两个题目:
HDU1159 http://acm.hdu.edu.cn/showproblem.php?pid=1159
代码如下:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
char a[1100],b[1100];
int len[1100][1100];
int main (){
while (scanf ("%s%s",a,b)!=EOF){
memset(len,0,sizeof(len));
for (int i=1;i<=strlen(a);i++){
for (int j=1;j<=strlen(b);j++){
if (a[i-1]==b[j-1]){
len[i][j]=len[i-1][j-1]+1;
}
else {
len[i][j]=max(len[i-1][j],len[i][j-1]);
}
}
}
printf ("%d\n",len[strlen(a)][strlen(b)]);
}
return 0;
}
POJ3356 http://poj.org/problem?id=3356
题目大意:给定两个序列 第一个序列最少经过多少次插入、删除、替换可转换位第二个序列
思路:求出两个序列的最长公共子序列 用第二个序列的长度减去最长公共子序列的长度 所得到长度便为要进行转换的长度
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int dp[1100][1100];
int main (){
int n,m;
char a[1100];
char b[1100];
while (scanf ("%d %s",&n,a)!=EOF){
scanf ("%d %s",&m,b);
memset(dp,0,sizeof(dp));
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if (a[i-1]==b[j-1]){
dp[i][j]=dp[i-1][j-1]+1;
}
else {
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
printf ("%d\n",m-dp[n][m]);
}
return 0;
}