1、最长公共子序列13 计科行知班 张宗雷 2013一、问题描述一个序列的子序列:该序列删除若干子序列后得到的序列。最长公共子序列:给定两个子序列 X 和 Y 当另一个序列 Z 既是 X 的子序列又是 Y 的子序列则称 Z 是 X 和 Y 的公共子序列。当 Z 是最长的一个公共子序列时 Z 称为 X 和 Y 的最长公共子序列。二、问题分析及推导过程1. 申明两个数组,用于保存比较的两个字符串;由于事先不知字符串大小,故动态的实现,这里用 C+的容器。2. 申明全局变量,二维数组 B 和数组 C。数组 C 用于保存计算 Xi 和 Yi 的 LCS 值;数组 B 保存当前的 C 是从哪个子问题得来的。
2、为此,定义一个枚举类型,用于标识不同的方向,分别为对角线、向上、向左和向左向上四个方向。3. 根据动态规划,实现一个函数 LCS_LENGTH,完成的功能是计算数组 B 和 C。具体过程是:先是动态申请二维数组 B 和 C,他们的行列长度都增加 1,目的就是方便计算。将 C 的第 0 行和第 0 列都赋上 0,即初始化。开始计算 Cij,以行为主,一次计算 C 的每一个元素,即将两个数组逐一比较。比较时就有两种情况,分别是若相等时,就将 Cij设置成 Ci-1j-1,同时将 Bij设置成DIAGONAL。若不相等时,比较 Ci-1j 和 Cij-1的值,又有三种情况:一是Ci-1j 与 Cij
3、-1相等, 就随便把某一个赋给 Cij,比如 Ci-1j,Bij 设置为 UP_LEFT;二是若 Ci-1j 大于 Cij-1,则将 Ci-1j赋给 Cij,并且将 Bij设置成 UP;最后是若 Ci-1j 小于 Cij-1,则将 Cij-1赋给 Cij,并且将 Bij设置成 LEFT。4. 根据第 3)步骤的结果,就可以找出所有 LCS 了。这里会用到回溯方法,具体实现可以用栈,也可以用递归。本人使用的是递归,代码简单、易懂。具体实现方法是:申请一个数组用于保存一个 LCS,这个数组会反复使用,因此,一旦找到一个就会立即将它输出。再设置一个变量 curpos 标识当前的数组下标,一个变量le
4、n 保存当前 LCS 数组的元素个数。扫描二维数组 B,从最后一个开始,判断 B的值,有四种情况:当 B 的值是 UP 时,就向上递归;当 B 的值是 LEFT 时,就向左递归;当 B 的值是向上或是向左时,这是存在两个选择,先左后上,或是先上后左;当 B 的值是对角线的时,此时 LCS 数组才保存当前的字符,len 加 1,继续沿对角线递归,递归完之后,len 减 1,回溯。若 len 为 LCS 的长度时,就输出。三、计算求解过程及算法实现#include #include #include #include #include using namespace std;int *C,*B;/
5、C 保存计算 Xi 和 Yi 的 LCS 值;B 保存当前的 C 是从哪个子问题得来的char *LCS;/保存一个最长公共子序列int len = 0;/回溯时用到的统计保存 LCS 数组当前长度enum DIAGONAL,UP,LEFT,UP_LEFT;/定义方向,分别是:对角线、向上、向左和向左向上/*LCS_LENGTH 函数,求出数组 C 和 B*/void LCS_LENGTH(vector X,vector Y,int m, int n)/计算 CC = new int*m;/动态分配二维数组B = new int*m;for(int i = 0; i Cij-1)/upCij
6、= Ci-1j;Bij = UP;else/leftCij = Cij-1;Bij = LEFT;/*Print_LCS 函数,打印出所有的 LCS*/void Print_LCS(int *B,vector X,int i,int j,int curpos,int maxLCS,ostream k = 0;k-)out:iterator beg, vector:iterator end) while(beg != end) cout X, Y;ifstream fin(“LCS.in“);/输入文件/char XMAXSIZE,YMAXSIZE;int count = 0;/实验的测试组数c
7、outcount;fin.get(s);/过滤一个换行符cout Common1,Common;利用 Common 来存储正要计算的 i 行和利用 Common1 来存储需要用到的 i-1 行,计算结束后,便将本行计算结果Common 中的值赋给上一行 Common1,此时 Common1 中存储的便是 i 行中的计算结果,然后 Common 便可以继续利用 Common1 中存储的值,来急需计算 i+1 行。然而,实际上,需要的辅助空间还可以更小(仅略多于表 c 一行的空间) ,为 min(m,n)项以及 O(1)的额外空间。这是因为在实际的计算 i 行第 j 个值的过程中,仅用到了 i-1 行中第 j 和 j-1 个值,所以只要用两个变量及时给出 i-1 行中第 j 和 j-1 个的值即可完成计算,这样便可以进一步缩小所需额外辅助空间。