0011算法笔记动态规划最长公共子序列问题LCS文档格式.docx
《0011算法笔记动态规划最长公共子序列问题LCS文档格式.docx》由会员分享,可在线阅读,更多相关《0011算法笔记动态规划最长公共子序列问题LCS文档格式.docx(20页珍藏版)》请在冰豆网上搜索。
=Yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。
这两个公共子序列中较长者为X和Y的最长公共子序列。
设数组b[i][j]记录c[i][j]的值由哪一个子问题的解得到的,从b[m][n]开始,依其值在数组b中搜索,当b[i][j]=1时,表示Xi和Yj的最长公共子序列是由Xi-1和Yj-1的最长公共子序列在尾部加上xi所得到的子序列。
当b[i][j]=2时,表示Xi和Yj的最长公共子序列与Xi-1和Yj-1的最长公共子序列相同。
当b[i][j]=3时,表示Xi和Yj的最长公共子序列与Xi和Yj-1的最长公共子序列相同。
代码如下:
[cpp]
viewplain
copy
1.//3d3-1
最长公共子序列问题
2.#include
"
stdafx.h"
3.#include
<
iostream>
4.using
namespace
std;
5.
6.const
int
M
=
7;
7.const
N
6;
8.
9.void
output(char
*s,int
n);
10.void
LCSLength(int
m,int
n,char
*x,char
*y,int
**c,int
**b);
11.void
LCS(int
i,int
j,char
*x,int
12.
13.int
main()
14.{
15.
//X={A,B,C,B,D,A,B}
16.
//Y={B,D,C,A,B,A}
17.
char
x[]
{'
'
'
A'
B'
C'
D'
};
18.
y[]
19.
20.
**c
new
*[M+1];
21.
**b
22.
for(int
i=0;
i<
=M;
i++)
23.
{
24.
c[i]
int[N+1];
25.
b[i]
26.
}
27.
28.
cout<
序列X:
endl;
29.
output(x,M);
30.
序列Y:
31.
output(y,N);
32.
33.
LCSLength(M,N,x,y,c,b);
34.
35.
序列X、Y最长公共子序列长度为:
c[M][N]<
36.
序列X、Y最长公共子序列为:
37.
LCS(M,N,x,b);
38.
39.}
40.
41.void
n)
42.{
43.
i=1;
=n;
44.
45.
s[i]<
;
46.
47.
48.}
49.
50.void
**b)
51.{
52.
i,j;
53.
54.
for(i=1;
=m;
55.
c[i][0]
0;
56.
57.
c[0][i]
58.
59.
60.
61.
for(j=1;
j<
j++)
62.
63.
if(x[i]==y[j])
64.
65.
c[i][j]=c[i-1][j-1]+1;
66.
b[i][j]=1;
67.
68.
else
if(c[i-1][j]>
=c[i][j-1])
69.
70.
c[i][j]=c[i-1][j];
71.
b[i][j]=2;
72.
73.
74.
75.
c[i][j]=c[i][j-1];
76.
b[i][j]=3;
77.
78.
79.
80.}
81.
82.void
83.{
84.
if(i==0
||
j==0)
85.
86.
return;
87.
88.
if(b[i][j]==1)
89.
90.
LCS(i-1,j-1,x,b);
91.
x[i]<
92.
93.
if(b[i][j]==2)
94.
95.
LCS(i-1,j,x,b);
96.
97.
98.
99.
LCS(i,j-1,x,b);
100.
101.}
LCSLength函数在计算最优值时,分别迭代X,Y构造数组b,c。
设数组每个元素单元计算耗费时间O
(1),则易得算法LCSLength的时间复杂度为O(mn)。
在算法LCS中,依据数组b的值回溯构造最优解,每一次递归调用使i,或j减小1。
从而算法的计算时间为O(m+n)。
LCS的回溯构造最优解过程如下图所示:
算法的改进:
对于一个具体问题,按照一般的算法设计策略设计出的算法,往往在算法的时间和空间需求上还可以改进。
这种改进,通常是利用具体问题的一些特殊性。
例如,在算法LCS_length和LCS中,可进一步将数组b省去。
事实上,数组元素c[i,j]的值仅由c[i-1][j-1],c[i-1][j]和c[i][j-1]三个值之一确定,而数组元素b[i][j]也只是用来指示c[i][j]究竟由哪个值确定。
因此,在算法LCS中,我们可以不借助于数组b而借助于数组c本身临时判断c[i][j]的值是由c[i-1][j-1],c[i-1][j]和c[i][j-1]中哪一个数值元素所确定,代价是Ο
(1)时间。
既然b对于算法LCS不是必要的,那么算法LCS_length便不必保存它。
这一来,可节省θ(mn)的空间,而LCS_length和LCS所需要的时间分别仍然是Ο(mn)和Ο(m+n)。
另外,如果只需要计算最长公共子序列的长度,则算法的空间需求还可大大减少。
事实上,在计算c[i][j]时,只用到数组c的第i行和第i-1行。
因此,只要用2行的数组空间就可以计算出最长公共子序列的长度。
更进一步的分析还可将空间需求减至min(m,n)。
1.//3d3-2
**c);
LCSLength(M,N,x,y,c);
LCS(M,N,x,c);
37.}
39.void
40.{
41.
42.
46.}
48.void
**c)
49.{
50.
51.
75.}
77.void
78.{
80.
82.
83.
if(c[i][j]==c[i-1][j-1]+1)
LCS(i-1,j-1,x,c);
LCS(i-1,j,x,c);
LCS(i,j-1,x,c);
96.}
运行结果如下:
从运行结果中可以看出,算法LCS回溯算法仅仅打印了其中一条最大公共子序列,如果存在多条公共子序列的情况下。
怎么解决?
对b[i][j]二维数组的取值添加一种可能,等于4,这代表了我们说的这种多支情况,那么回溯的时候可以根据这个信息打印更多可能的选择。
你从(7,6)点开始按b[i][j]的值指示的方向回溯,把所有的路径遍历一遍,如果是能达到起点(1,1)的路径,就是LCS了,有多少条打印多少条。
可是,在回溯路径的时候,如果采用一般的全搜索,会进行了很多无用功。
即重复了很多,且会遍历了一些无效路径,因为这些路径最终不会到达终点(1,1),因此加大算法复杂度和时间消耗。
博文《求所有最大公共子序列的算法实现》给出了一种"
矩行搜索"
的解决办法降低了算法的复杂度。
算法主要是利用两个栈store,print,一个用来储存节点,一个用来打印节点。
栈的实现代码如下(文件Stack.h):
1./**
2.
头文件------head
file
3.
*/
4.
5.template
class
T>
6.class
StackNode{
7.
public:
T
data;
9.
StackNode
*next;
10.};
11.
12.template
13.class
Stack{
14.
Stack(void):
top(NULL){}
bool
IsEmpty(void)
const{
return
top==NULL;
void
Push(const
data);
Pop(T
*data);
Peek(T
*data)
const;
StackNode<
*
GetStackNode();
private:
*top;
23.};
25.template
26.StackNode<
Stack<
:
GetStackNode(){
top;
28.}
30.template
31.void
data){
*node
();
node->
data
next
top
node;
36.}
38.template
39.bool
if(IsEmpty())
false;
*data
top->
true;
43.}
45.template
46.bool
*data){
48.
next;
delete(node);
53.}
所有最长公共子序列问题LCS矩阵搜索代码如下:
1.//3d3-3
所有最长公共子序列问题LCS
矩阵搜索
stack.h"
4.#include
5.using
6.
7.typedef
**Matrix;
8.const
9.const
10.
11.typedef
struct
_Element
12.{
13.
lcslen;
//当前节点的LCS长度
row;
//当前节点的行坐标
col;
//当前节点的列坐标
16.}Element;
18.void
20.Element
CreateElement(int
nlen,
row,
col);
22.Matrix
GreateMatrix(int
23.void
DeleteMatrix(Matrix
p,
row);
25.void
PrintStack(Stack<
Element>
*ps,
*str,
len);
26.void
SearchE(Matrix
pb,
curposx,
curposy,
&
eposx,
eposy,
ntype);
28.void
*y,Matrix
pc,Matrix
pb);
29.void
LCS(char
*x,
Matrix
pc,
//矩阵搜索回溯
3