动态规划之四:最长公共子序列

问题:已知两个序列的长度分别为m、n,求取这两个序列的最长公共子序列LCS(longest common sequence)的长度?

示例描述:

    输入:

         第一行输入两个整数分别为n、m,它们分别代表序列source以及dest 的长度

         第二行输入序列source的值

         第三行输入序列dest的值

  输出:

        输出最长子序列的长度。

实例:

  输入:

       8 9

扫描二维码关注公众号,回复: 2830865 查看本文章

       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的最长公共子序列

如果序列XY,则Sk是Xn与Ym-1的最长公共子序列,或者是Xn-1与Ym的最长公共子序列

通过上面分析我们可以得到如何划分子问题,即分三种情况:

其一序列X=Y,Sk=X=Y;

其二序列XY情况下,Sk可能是Xn与Ym-1的最长公共子序列

其三序列XY情况下,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


猜你喜欢

转载自blog.csdn.net/zjx_cfbx/article/details/79967325