基本题一:最长公共子序列问题
一、实验目的与要求
1、熟悉最长公共子序列问题的算法;
2、初步掌握动态规划算法;
二、实验题
若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。
给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。
三、实验提示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
include
"stdlib.h"
#include "string.h"
void
LCSLength(
char
*x ,
char
*y,intm,
int
n,
int
**c,
int
**b)
{
inti ,j;
for
(i = 1; i<= m; i++) c[i][0] = 0;
for
(i = 1; i<= n; i++) c[0][i] = 0;
for
(i = 1; i<= m; i++)
for
(j = 1; j <= n; j++)
{
if
(x[i]==y[j])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
else
if
(c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=2;
}
else
{ c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
void
LCS(inti ,
int
j,
char
*x ,
int
**b)
{
if
(i ==0 || j==0)
return
;
if
(b[i][j]== 1)
{
LCS(i-1,j-1,x,b);
printf
(
"%c"
,x[i]);
}
else
if
(b[i][j]== 2)
LCS(i-1,j,x,b);
else
LCS(i,j-1,x,b);
}
|
四、题目分析
在求最长公共子序列中,我们可以看出如下规律:
设序列X={x1,x2,…,xm}和Y={y1,y2,…,yn}的最长公共子序列为Z={z1,z2,…,zk} ,则
(1)若xm=yn,则zk=xm=yn,且zk-1是xm-1和yn-1的最长公共子序列。
(2)若xm≠yn且zk≠xm,则Z是xm-1和Y的最长公共子序列。(即:Z是X序列中前m个元素所组成的序列与Y序列的最长公共子序列)
(3)若xm≠yn且zk≠yn,则Z是X和yn-1的最长公共子序列。(即:Z是Y序列中前n个元素所组成的序列与X序列的最长公共子序列)
由上面三个条件可得如下公式:
C[][]用来记录最长公共子序列的长度,则:
c[i][j] = <1> 0; (当i、j = 0时);
<2> c[i-1][j-1] + 1; (当i、j > 0 且 Xi = Yj时)(即第i个X序列元素与第j个Y元素相等)
<3> max(c[i][j-1] , c[i-1][j]) (当i、j > 0 且 Xi != Yj时)(当Xi与Yj不等时,取两个式子的最大值,若两者相等则默认取第一个)
五,源代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
importjava.util.*;
import
java.io.*;
public
class
LCS
{
public
static
void
main(String[] args) {
String s1 =
"ABCBDAB"
;
String s2 =
"BDCABA"
;
LCS cms =
new
LCS();
String[] x = cms.init(s1);
String[] y = cms.init(s2);
int
[][] b =
new
int
[x.length][y.length];
System.out.println(
"最大子序列的长度为:"
+lcsLength(x, y, b));
System.out.println(
"最大子序列为:"
);
lcs(x.length-
1
, y.length-
1
, x, b);
}
public
static
void
lcs(inti,
int
j, String[] x,
int
[][] b) {
if
(i ==
0
|| j ==
0
)
return
;
if
(b[i][j] ==
1
) {
lcs(i -
1
, j -
1
, x, b);
System.out.print(x[i]+
" "
);
}
else
if
(b[i][j] ==
2
)
lcs(i -
1
, j, x, b);
else
lcs(i, j -
1
, x, b);
}
private
String[] init(String str){
String temp = str;
String[] s = temp.split(
""
);
return
s;
}
public
static
intlcsLength(String[] x, String[] y,
int
[][] b) {
int
m = x.length -
1
;
int
n = y.length -
1
;
int
[][] c =
new
int
[m +
1
][n +
1
];
for
(inti =
1
; i<= m; i++){
c[i][
0
] =
0
;
}
for
(inti =
1
; i<= n; i++)
c[
0
][i] =
0
;
for
(inti =
1
; i<= m; i++) {
for
(
int
j =
1
; j <= n; j++) {
if
(x[i].equals(y[j])) {
c[i][j] = c[i -
1
][j -
1
] +
1
;
b[i][j] =
1
;
}
else
if
(c[i -
1
][j] >= c[i][j -
1
]) {
c[i][j] = c[i -
1
][j];
b[i][j] =
2
;
}
else
{
c[i][j] = c[i][j -
1
];
b[i][j] =
3
;
}
}
}
return
c[m][n];
}
}
|
结果:
本文转自 梦朝思夕 51CTO博客,原文链接:http://blog.51cto.com/qiangmzsx/824842