问题:已知两个序列的长度分别为m、n,求取这两个序列的最长公共子序列LCS(longest common sequence)的长度?
示例描述:
输入:
第一行输入两个整数分别为n、m,它们分别代表序列source以及dest 的长度
第二行输入序列source的值
第三行输入序列dest的值
输出:
输出最长子序列的长度。
实例:
输入:
8 9
1 3 4 5 6 7 7 8
3 5 7 4 8 6 7 8 2
输出:
5
基本概念:
子序列:将一个给定的序列的零个或多个元素丢掉之后得到的结果。
子串:一个给定序列的任意连续元素组成的子序列。
下面使用图例进行概念说明:
假设S(S1,S2,...,Sk)是序列X(x1,x2,...,xn)与Y(y1,y2,...,ym)的最长公共子序列,我们可以得到:
如果序列X=Y,则序列S=X=Y;有Sk-1是Xn-1与Ym-1的最长公共子序列
如果序列X≠Y,则Sk是Xn与Ym-1的最长公共子序列,或者是Xn-1与Ym的最长公共子序列
通过上面分析我们可以得到如何划分子问题,即分三种情况:
其一序列X=Y,Sk=X=Y;
其二序列X≠Y情况下,Sk可能是Xn与Ym-1的最长公共子序列
其三序列X≠Y情况下,Sk可能是Xn-1与Ym的最长公共子序列
使用形式化递推公式进行描述为:
如果我们直接对上述地推公式进行编程将达到指数级别,因此利用动态规划的思想,使用一个表格来暂存其中间结果,可得其状态转移函数为
其中,当i=0或者j=0时,为该问题的边界。
程序结果为:
#include<iostream>
using namespace std;
#define size 100 //表格的大小
int main() {
int a[size][size];//对表格进行初始化
int source[size],dest[size];//定义序列元素类型
int n, m;
cin >> n >> m; //n代表行,m代表列
for (int i = 0; i < n; i++)
cin >> source[i]; //代表匹配串
for (int i = 0; i < m; i++)
cin >> dest[i]; //代表主串
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++)
a[i][j] = 0; //对表格进行初始化
}
for (int i = 1; i <= n; i++) {
for(int j=1;j<=m;j++)
if (source[i-1]==dest[j-1]) {
a[i][j] = a[i - 1][j - 1] + 1;
}
else {
a[i][j] = a[i - 1][j] > a[i][j - 1] ? a[i - 1][j] : a[i][j - 1];
}
}
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= m; j++)
cout << a[i][j] << "\t";
cout << endl;
}
cout <<"最长子序列的长度为:" <<a[n][m]<< endl;
system("pause");
}
参考:https://blog.csdn.net/hrn1216/article/details/51534607